From e01dda9bafb906123fb4fdc9c951e5da5c40a53b Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 21 Feb 2024 18:45:10 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20CRM=EF=BC=9A=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E5=95=86=E6=9C=BA=E7=9A=84=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/crm/enums/ErrorCodeConstants.java | 1 + .../admin/business/CrmBusinessController.java | 98 ++++++++--- .../vo/business/CrmBusinessExcelVO.java | 75 --------- .../vo/business/CrmBusinessRespVO.java | 157 +++++++++++++----- .../vo/business/CrmBusinessSaveReqVO.java | 62 +++---- .../admin/contract/CrmContractController.java | 2 +- .../admin/product/CrmProductController.java | 53 ++++-- .../product/vo/product/CrmProductRespVO.java | 3 +- .../vo/product/CrmProductSaveReqVO.java | 6 +- .../convert/business/CrmBusinessConvert.java | 23 --- .../convert/product/CrmProductConvert.java | 46 ----- .../dataobject/business/CrmBusinessDO.java | 97 +++++------ .../business/CrmBusinessProductDO.java | 26 +-- .../crm/dal/dataobject/clue/CrmClueDO.java | 2 +- .../dal/dataobject/product/CrmProductDO.java | 6 +- .../crm/dal/mysql/business/package-info.java | 4 - .../crm/dal/mysql/contact/package-info.java | 4 - .../dal/mysql/product/CrmProductMapper.java | 24 +-- .../service/business/CrmBusinessService.java | 9 + .../business/CrmBusinessServiceImpl.java | 124 +++++++------- .../business/CrmBusinessStatusService.java | 14 +- .../CrmBusinessStatusServiceImpl.java | 5 + .../CrmBusinessStatusTypeService.java | 13 ++ .../CrmBusinessStatusTypeServiceImpl.java | 11 +- .../contract/CrmContractServiceImpl.java | 3 +- .../product/CrmProductCategoryService.java | 15 +- .../service/product/CrmProductService.java | 33 +++- .../product/CrmProductServiceImpl.java | 49 ++++-- 28 files changed, 527 insertions(+), 438 deletions(-) delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessExcelVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/product/CrmProductConvert.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/package-info.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/package-info.java 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 7a04208fb..a484c778f 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 @@ -67,6 +67,7 @@ public interface ErrorCodeConstants { // ========== 产品 1_020_008_000 ========== ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_020_008_000, "产品不存在"); ErrorCode PRODUCT_NO_EXISTS = new ErrorCode(1_020_008_001, "产品编号已存在"); + ErrorCode PRODUCT_NOT_ENABLE = new ErrorCode(1_020_008_002, "产品【{}】已禁用"); // ========== 产品分类 1_020_009_000 ========== ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_020_009_000, "产品分类不存在"); 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 c85c151f5..91b8e95dd 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 @@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.crm.controller.admin.business; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +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; @@ -10,15 +12,21 @@ import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusi import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessRespVO; import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessSaveReqVO; import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessTransferReqVO; -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.CrmBusinessProductDO; import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusTypeDO; import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; import cn.iocoder.yudao.module.crm.service.business.CrmBusinessStatusService; import cn.iocoder.yudao.module.crm.service.business.CrmBusinessStatusTypeService; import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; +import cn.iocoder.yudao.module.crm.service.product.CrmProductService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -30,13 +38,15 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.io.IOException; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.stream.Stream; 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.framework.common.pojo.PageParam.PAGE_SIZE_NONE; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CUSTOMER_NOT_EXISTS; @@ -55,6 +65,13 @@ public class CrmBusinessController { private CrmBusinessStatusTypeService businessStatusTypeService; @Resource private CrmBusinessStatusService businessStatusService; + @Resource + private CrmProductService productService; + + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; @PostMapping("/create") @Operation(summary = "创建商机") @@ -86,9 +103,25 @@ public class CrmBusinessController { @PreAuthorize("@ss.hasPermission('crm:business:query')") public CommonResult getBusiness(@RequestParam("id") Long id) { CrmBusinessDO business = businessService.getBusiness(id); - return success(BeanUtils.toBean(business, CrmBusinessRespVO.class)); + return success(buildBusinessDetail(business)); } + private CrmBusinessRespVO buildBusinessDetail(CrmBusinessDO business) { + if (business == null) { + return null; + } + CrmBusinessRespVO businessVO = buildBusinessDetailList(Collections.singletonList(business)).get(0); + // 拼接产品项 + List businessProducts = businessService.getBusinessProductListByBusinessId(businessVO.getId()); + Map productMap = productService.getProductMap( + convertSet(businessProducts, CrmBusinessProductDO::getProductId)); + businessVO.setProducts(BeanUtils.toBean(businessProducts, CrmBusinessRespVO.Product.class, businessProductVO -> + MapUtils.findAndThen(productMap, businessProductVO.getProductId(), + product -> businessProductVO.setProductNo(product.getNo()).setProductUnit(product.getUnit())))); + return businessVO; + } + + // TODO 芋艿:处理下 @GetMapping("/list-by-ids") @Operation(summary = "获得商机列表") @Parameter(name = "ids", description = "编号", required = true, example = "[1024]") @@ -97,6 +130,7 @@ public class CrmBusinessController { return success(BeanUtils.toBean(businessService.getBusinessList(ids, getLoginUserId()), CrmBusinessRespVO.class)); } + // TODO 芋艿:处理下 @GetMapping("/simple-all-list") @Operation(summary = "获得联系人的精简列表") @PreAuthorize("@ss.hasPermission('crm:contact:query')") @@ -113,7 +147,7 @@ public class CrmBusinessController { @PreAuthorize("@ss.hasPermission('crm:business:query')") public CommonResult> getBusinessPage(@Valid CrmBusinessPageReqVO pageVO) { PageResult pageResult = businessService.getBusinessPage(pageVO, getLoginUserId()); - return success(buildBusinessDetailPageResult(pageResult)); + return success(new PageResult<>(buildBusinessDetailList(pageResult.getList()), pageResult.getTotal())); } @GetMapping("/page-by-customer") @@ -123,7 +157,7 @@ public class CrmBusinessController { throw exception(CUSTOMER_NOT_EXISTS); } PageResult pageResult = businessService.getBusinessPageByCustomerId(pageReqVO); - return success(buildBusinessDetailPageResult(pageResult)); + return success(new PageResult<>(buildBusinessDetailList(pageResult.getList()), pageResult.getTotal())); } @GetMapping("/page-by-contact") @@ -131,7 +165,7 @@ public class CrmBusinessController { @PreAuthorize("@ss.hasPermission('crm:business:query')") public CommonResult> getBusinessContactPage(@Valid CrmBusinessPageReqVO pageReqVO) { PageResult pageResult = businessService.getBusinessPageByContact(pageReqVO); - return success(buildBusinessDetailPageResult(pageResult)); + return success(new PageResult<>(buildBusinessDetailList(pageResult.getList()), pageResult.getTotal())); } @GetMapping("/export-excel") @@ -141,29 +175,43 @@ public class CrmBusinessController { public void exportBusinessExcel(@Valid CrmBusinessPageReqVO exportReqVO, HttpServletResponse response) throws IOException { exportReqVO.setPageSize(PAGE_SIZE_NONE); - PageResult pageResult = businessService.getBusinessPage(exportReqVO, getLoginUserId()); + List list = businessService.getBusinessPage(exportReqVO, getLoginUserId()).getList(); // 导出 Excel ExcelUtils.write(response, "商机.xls", "数据", CrmBusinessRespVO.class, - buildBusinessDetailPageResult(pageResult).getList()); + buildBusinessDetailList(list)); } - /** - * 构建详细的商机分页结果 - * - * @param pageResult 简单的商机分页结果 - * @return 详细的商机分页结果 - */ - private PageResult buildBusinessDetailPageResult(PageResult pageResult) { - if (CollUtil.isEmpty(pageResult.getList())) { - return PageResult.empty(pageResult.getTotal()); + private List buildBusinessDetailList(List list) { + if (CollUtil.isEmpty(list)) { + return Collections.emptyList(); } - 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); + // 1.1 获取客户列表 + Map customerMap = customerService.getCustomerMap( + convertSet(list, CrmBusinessDO::getCustomerId)); + // 1.2 获取创建人、负责人列表 + Map userMap = adminUserApi.getUserMap(convertListByFlatMap(list, + contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); + Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); + // 1.3 获得商机状态组 + Map statusTypeMap = businessStatusTypeService.getBusinessStatusTypeMap( + convertSet(list, CrmBusinessDO::getStatusTypeId)); + Map statusMap = businessStatusService.getBusinessStatusMap( + convertSet(list, CrmBusinessDO::getStatusId)); + // 2. 拼接数据 + return BeanUtils.toBean(list, CrmBusinessRespVO.class, businessVO -> { + // 2.1 设置客户名称 + MapUtils.findAndThen(customerMap, businessVO.getCustomerId(), customer -> businessVO.setCustomerName(customer.getName())); + // 2.2 设置创建人、负责人名称 + MapUtils.findAndThen(userMap, NumberUtils.parseLong(businessVO.getCreator()), + user -> businessVO.setCreatorName(user.getNickname())); + MapUtils.findAndThen(userMap, businessVO.getOwnerUserId(), user -> { + businessVO.setOwnerUserName(user.getNickname()); + MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> businessVO.setOwnerUserDeptName(dept.getName())); + }); + // 2.3 设置商机状态 + MapUtils.findAndThen(statusTypeMap, businessVO.getStatusTypeId(), statusType -> businessVO.setStatusTypeName(statusType.getName())); + MapUtils.findAndThen(statusMap, businessVO.getStatusId(), status -> businessVO.setStatusName(status.getName())); + }); } @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/CrmBusinessExcelVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessExcelVO.java deleted file mode 100644 index a11949ecd..000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessExcelVO.java +++ /dev/null @@ -1,75 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; - -import com.alibaba.excel.annotation.ExcelProperty; -import lombok.Data; - -import java.math.BigDecimal; -import java.time.LocalDateTime; -import java.util.Set; - -/** - * 商机 Excel VO - * - * @author ljlleo - */ -@Data -public class CrmBusinessExcelVO { - - @ExcelProperty("主键") - private Long id; - - @ExcelProperty("商机名称") - private String name; - - @ExcelProperty("商机状态类型编号") - private Long statusTypeId; - - @ExcelProperty("商机状态编号") - private Long statusId; - - @ExcelProperty("下次联系时间") - private LocalDateTime contactNextTime; - - @ExcelProperty("客户编号") - private Long customerId; - - @ExcelProperty("预计成交日期") - private LocalDateTime dealTime; - - @ExcelProperty("商机金额") - private BigDecimal price; - - @ExcelProperty("整单折扣") - private BigDecimal discountPercent; - - @ExcelProperty("产品总金额") - private BigDecimal productPrice; - - @ExcelProperty("备注") - private String remark; - - @ExcelProperty("负责人的用户编号") - private Long ownerUserId; - - @ExcelProperty("创建时间") - private LocalDateTime createTime; - - @ExcelProperty("只读权限的用户编号数组") - private Set roUserIds; - - @ExcelProperty("读写权限的用户编号数组") - private Set rwUserIds; - - @ExcelProperty("1赢单2输单3无效") - private Integer endStatus; - - @ExcelProperty("结束时的备注") - private String endRemark; - - @ExcelProperty("最后跟进时间") - private LocalDateTime contactLastTime; - - @ExcelProperty("跟进状态") - private Integer followUpStatus; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessRespVO.java index d3b6ab2fb..41829360a 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessRespVO.java @@ -1,69 +1,144 @@ package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; import lombok.Data; -import org.springframework.format.annotation.DateTimeFormat; +import lombok.NoArgsConstructor; import java.math.BigDecimal; import java.time.LocalDateTime; +import java.util.List; -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; - -@Schema(description = "管理后台 - 商机 Response VO") +@Schema(description = "管理后台 - CRM 商机 Response VO") @Data +@ExcelIgnoreUnannotated public class CrmBusinessRespVO { - @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "32129") + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32129") + @ExcelProperty("编号") private Long id; @Schema(description = "商机名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") - @NotNull(message = "商机名称不能为空") + @ExcelProperty("商机名称") private String name; - @Schema(description = "商机状态类型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25714") - @NotNull(message = "商机状态类型不能为空") - private Long statusTypeId; - - @Schema(description = "商机状态编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320") - @NotNull(message = "商机状态不能为空") - private Long statusId; - - @Schema(description = "下次联系时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime contactNextTime; - @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10299") - @NotNull(message = "客户不能为空") private Long customerId; - - @Schema(description = "预计成交日期") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime dealTime; - - @Schema(description = "商机金额", example = "12371") - private Integer price; - - // TODO @ljileo:折扣使用 Integer 类型,存储时,默认 * 100;展示的时候,前端需要 / 100;避免精度丢失问题 - @Schema(description = "整单折扣") - private Integer discountPercent; - - @Schema(description = "产品总金额", example = "12025") - private BigDecimal productPrice; - - @Schema(description = "备注", example = "随便") - private String remark; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime createTime; - @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @ExcelProperty("客户名称") private String customerName; + @Schema(description = "跟进状态", requiredMode = Schema.RequiredMode.REQUIRED, example ="true") + @ExcelProperty("跟进状态") + private Boolean followUpStatus; + + @Schema(description = "最后跟进时间") + @ExcelProperty("最后跟进时间") + private LocalDateTime contactLastTime; + + @Schema(description = "下次联系时间") + @ExcelProperty("下次联系时间") + private LocalDateTime contactNextTime; + + @Schema(description = "负责人的用户编号", example = "25682") + @ExcelProperty("负责人的用户编号") + private Long ownerUserId; + @Schema(description = "负责人名字", example = "25682") + @ExcelProperty("负责人名字") + private String ownerUserName; + @Schema(description = "负责人部门") + @ExcelProperty("负责人部门") + private String ownerUserDeptName; + + @Schema(description = "商机状态类型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25714") + private Long statusTypeId; @Schema(description = "状态类型名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "进行中") + @ExcelProperty("商机状态类型") private String statusTypeName; + @Schema(description = "商机状态编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320") + private Long statusId; @Schema(description = "状态名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "跟进中") + @ExcelProperty("商机状态") private String statusName; + @Schema + @ExcelProperty("1赢单2输单3无效") + private Integer endStatus; + + @ExcelProperty("结束时的备注") + private String endRemark; + + @Schema(description = "预计成交日期") + @ExcelProperty("预计成交日期") + private LocalDateTime dealTime; + + @Schema(description = "产品总金额", example = "12025") + @ExcelProperty("产品总金额") + private BigDecimal totalProductPrice; + + @Schema(description = "整单折扣") + @ExcelProperty("整单折扣") + private BigDecimal discountPercent; + + @Schema(description = "商机总金额", example = "12371") + @ExcelProperty("商机总金额") + private BigDecimal totalPrice; + + @Schema(description = "备注", example = "随便") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "创建人", example = "1024") + @ExcelProperty("创建人") + private String creator; + @Schema(description = "创建人名字", example = "芋道源码") + @ExcelProperty("创建人名字") + private String creatorName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("更新时间") + private LocalDateTime updateTime; + + @Schema(description = "产品列表") + private List products; + + @Schema(description = "产品列表") + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class Product { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") + private Long id; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") + private Long productId; + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + private String productName; + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") + private String productNo; + @Schema(description = "产品单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + private Integer productUnit; + + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") + private BigDecimal productPrice; + + @Schema(description = "合同价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") + private BigDecimal businessPrice; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") + private Integer count; + + @Schema(description = "总计价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") + private BigDecimal totalPrice; + + } + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessSaveReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessSaveReqVO.java index 0be6264eb..b9816a8fc 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessSaveReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessSaveReqVO.java @@ -1,8 +1,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.crm.enums.business.CrmBizEndStatus; import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerParseFunction; +import cn.iocoder.yudao.module.crm.framework.operatelog.core.SysAdminUserParseFunction; import com.mzt.logapi.starter.annotation.DiffLogField; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; @@ -29,75 +28,68 @@ public class CrmBusinessSaveReqVO { @NotNull(message = "商机名称不能为空") private String name; - @Schema(description = "商机状态类型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25714") - @DiffLogField(name = "商机状态") - @NotNull(message = "商机状态类型不能为空") - private Long statusTypeId; - - @Schema(description = "商机状态编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320") - @DiffLogField(name = "商机状态") - @NotNull(message = "商机状态不能为空") - private Long statusId; + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10299") + @DiffLogField(name = "客户", function = CrmCustomerParseFunction.NAME) + @NotNull(message = "客户不能为空") + private Long customerId; @Schema(description = "下次联系时间") @DiffLogField(name = "下次联系时间") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime contactNextTime; - @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10299") - @DiffLogField(name = "客户", function = CrmCustomerParseFunction.NAME) - @NotNull(message = "客户不能为空") - private Long customerId; + @Schema(description = "负责人用户编号", example = "14334") + @NotNull(message = "负责人不能为空") + @DiffLogField(name = "负责人", function = SysAdminUserParseFunction.NAME) + private Long ownerUserId; + + @Schema(description = "商机状态类型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25714") + @DiffLogField(name = "商机状态") + @NotNull(message = "商机状态类型不能为空") + private Long statusTypeId; @Schema(description = "预计成交日期") @DiffLogField(name = "预计成交日期") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime dealTime; - @Schema(description = "商机金额", example = "12371") - @DiffLogField(name = "商机金额") - private Integer price; - @Schema(description = "整单折扣") @DiffLogField(name = "整单折扣") - private Integer discountPercent; - - @Schema(description = "产品总金额", example = "12025") - @DiffLogField(name = "产品总金额") - private BigDecimal productPrice; + @NotNull(message = "整单折扣不能为空") + private BigDecimal discountPercent; @Schema(description = "备注", example = "随便") @DiffLogField(name = "备注") private String remark; - @Schema(description = "结束状态", example = "1") - @InEnum(CrmBizEndStatus.class) - private Integer endStatus; - @Schema(description = "联系人编号", example = "110") private Long contactId; // 使用场景,在【联系人详情】添加商机时,如果需要关联两者,需要传递 contactId 字段 - // TODO @puhui999:传递 items 就行啦; @Schema(description = "产品列表") - private List productItems; + private List products; @Schema(description = "产品列表") @Data @NoArgsConstructor @AllArgsConstructor - public static class CrmBusinessProductItem { + public static class Product { @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") @NotNull(message = "产品编号不能为空") - private Long id; + private Long productId; + + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") + @NotNull(message = "产品单价不能为空") + private BigDecimal productPrice; + + @Schema(description = "合同价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") + @NotNull(message = "合同价格不能为空") + private BigDecimal businessPrice; @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") @NotNull(message = "产品数量不能为空") private Integer count; - @Schema(description = "产品折扣") - private Integer discountPercent; - } } 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 ef0aa849a..d691a1701 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 @@ -179,7 +179,7 @@ public class CrmContractController { if (contractList.size() == 1) { List contractProductList = contractService.getContractProductListByContractId(contractList.get(0).getId()); contractProductMap = convertMap(contractProductList, CrmContractProductDO::getProductId); - productList = productService.getProductListByIds(convertSet(contractProductList, CrmContractProductDO::getProductId)); + productList = productService.getProductList(convertSet(contractProductList, CrmContractProductDO::getProductId)); } return CrmContractConvert.INSTANCE.convertList(contractList, userMap, customerList, contactMap, businessMap, contractProductMap, productList); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/CrmProductController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/CrmProductController.java index 94774373d..91d31de7a 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/CrmProductController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/CrmProductController.java @@ -1,16 +1,17 @@ package cn.iocoder.yudao.module.crm.controller.admin.product; import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.SetUtils; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +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.product.vo.product.CrmProductPageReqVO; import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductRespVO; import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductSaveReqVO; -import cn.iocoder.yudao.module.crm.convert.product.CrmProductConvert; import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductCategoryDO; import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; import cn.iocoder.yudao.module.crm.service.product.CrmProductCategoryService; @@ -34,10 +35,9 @@ import java.util.Map; import java.util.stream.Stream; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; +import static java.util.Collections.singletonList; @Tag(name = "管理后台 - CRM 产品") @RestController @@ -49,6 +49,7 @@ public class CrmProductController { private CrmProductService productService; @Resource private CrmProductCategoryService productCategoryService; + @Resource private AdminUserApi adminUserApi; @@ -82,21 +83,30 @@ public class CrmProductController { @PreAuthorize("@ss.hasPermission('crm:product:query')") public CommonResult getProduct(@RequestParam("id") Long id) { CrmProductDO product = productService.getProduct(id); + return success(buildProductDetail(product)); + } + + private CrmProductRespVO buildProductDetail(CrmProductDO product) { if (product == null) { - return success(null); + return null; } - Map userMap = adminUserApi.getUserMap( - SetUtils.asSet(Long.valueOf(product.getCreator()), product.getOwnerUserId())); - CrmProductCategoryDO category = productCategoryService.getProductCategory(product.getCategoryId()); - return success(CrmProductConvert.INSTANCE.convert(product, userMap, category)); + return buildProductDetailList(singletonList(product)).get(0); + } + + @GetMapping("/simple-list") + @Operation(summary = "获得产品精简列表", description = "只包含被开启的产品,主要用于前端的下拉选项") + public CommonResult> getProductSimpleList() { + List list = productService.getProductListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(convertList(list, product -> new CrmProductRespVO().setId(product.getId()).setName(product.getName()) + .setUnit(product.getUnit()).setNo(product.getNo()).setPrice(product.getPrice()))); } @GetMapping("/page") @Operation(summary = "获得产品分页") @PreAuthorize("@ss.hasPermission('crm:product:query')") public CommonResult> getProductPage(@Valid CrmProductPageReqVO pageVO) { - PageResult pageResult = productService.getProductPage(pageVO, getLoginUserId()); - return success(new PageResult<>(getProductDetailList(pageResult.getList()), pageResult.getTotal())); + PageResult pageResult = productService.getProductPage(pageVO); + return success(new PageResult<>(buildProductDetailList(pageResult.getList()), pageResult.getTotal())); } @GetMapping("/export-excel") @@ -106,21 +116,30 @@ public class CrmProductController { public void exportProductExcel(@Valid CrmProductPageReqVO exportReqVO, HttpServletResponse response) throws IOException { exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); - List list = productService.getProductPage(exportReqVO, getLoginUserId()).getList(); + List list = productService.getProductPage(exportReqVO).getList(); // 导出 Excel ExcelUtils.write(response, "产品.xls", "数据", CrmProductRespVO.class, - getProductDetailList(list)); + buildProductDetailList(list)); } - private List getProductDetailList(List list) { + private List buildProductDetailList(List list) { if (CollUtil.isEmpty(list)) { return Collections.emptyList(); } + // 1.1 获得用户信息 Map userMap = adminUserApi.getUserMap( convertSetByFlatMap(list, user -> Stream.of(Long.valueOf(user.getCreator()), user.getOwnerUserId()))); - List productCategoryList = productCategoryService.getProductCategoryList( + // 1.2 获得分类信息 + Map categoryMap = productCategoryService.getProductCategoryMap( convertSet(list, CrmProductDO::getCategoryId)); - return CrmProductConvert.INSTANCE.convertList(list, userMap, productCategoryList); + // 2. 拼接数据 + return BeanUtils.toBean(list, CrmProductRespVO.class, productVO -> { + // 2.1 设置用户信息 + MapUtils.findAndThen(userMap, productVO.getOwnerUserId(), user -> productVO.setOwnerUserName(user.getNickname())); + MapUtils.findAndThen(userMap, Long.valueOf(productVO.getCreator()), user -> productVO.setCreatorName(user.getNickname())); + // 2.2 设置分类名称 + MapUtils.findAndThen(categoryMap, productVO.getCategoryId(), category -> productVO.setCategoryName(category.getName())); + }); } } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductRespVO.java index ceca3e5a0..1f659aa77 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductRespVO.java @@ -8,6 +8,7 @@ import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import java.math.BigDecimal; import java.time.LocalDateTime; @Schema(description = "管理后台 - CRM 产品 Response VO") @@ -34,7 +35,7 @@ public class CrmProductRespVO { @Schema(description = "价格, 单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") @ExcelProperty("价格,单位:分") - private Long price; + private BigDecimal price; @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "上架") @ExcelProperty(value = "单位", converter = DictConvert.class) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductSaveReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductSaveReqVO.java index 01b2ae443..ef6d5824d 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductSaveReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductSaveReqVO.java @@ -7,6 +7,8 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.Data; +import java.math.BigDecimal; + @Schema(description = "管理后台 - CRM 产品创建/修改 Request VO") @Data public class CrmProductSaveReqVO { @@ -28,10 +30,10 @@ public class CrmProductSaveReqVO { @DiffLogField(name = "单位", function = CrmProductUnitParseFunction.NAME) private Integer unit; - @Schema(description = "价格, 单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") + @Schema(description = "价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") @NotNull(message = "价格不能为空") @DiffLogField(name = "价格") - private Long price; + private BigDecimal price; @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "上架") @NotNull(message = "状态不能为空") 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 d7f990043..c86726412 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,14 +1,8 @@ package cn.iocoder.yudao.module.crm.convert.business; -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.business.vo.business.CrmBusinessRespVO; import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessTransferReqVO; import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusTypeDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; import org.mapstruct.Mapper; @@ -16,9 +10,6 @@ import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; /** * 商机 Convert @@ -33,20 +24,6 @@ public interface CrmBusinessConvert { @Mapping(target = "bizId", source = "reqVO.id") CrmPermissionTransferReqBO convert(CrmBusinessTransferReqVO reqVO, Long userId); - default PageResult convertPage(PageResult pageResult, List customerList, - List statusTypeList, List statusList) { - 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); - voPageResult.getList().forEach(type -> type - .setCustomerName(customerMap.get(type.getCustomerId())) - .setStatusTypeName(statusTypeMap.get(type.getStatusTypeId())) - .setStatusName(statusMap.get(type.getStatusId()))); - return voPageResult; - } - @Mapping(target = "id", source = "reqBO.bizId") CrmBusinessDO convert(CrmUpdateFollowUpReqBO reqBO); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/product/CrmProductConvert.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/product/CrmProductConvert.java deleted file mode 100644 index 2165a208f..000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/product/CrmProductConvert.java +++ /dev/null @@ -1,46 +0,0 @@ -package cn.iocoder.yudao.module.crm.convert.product; - -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductRespVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductCategoryDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import org.mapstruct.Mapper; -import org.mapstruct.factory.Mappers; - -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; - -/** - * 产品 Convert - * - * @author ZanGe丶 - */ -@Mapper -public interface CrmProductConvert { - - CrmProductConvert INSTANCE = Mappers.getMapper(CrmProductConvert.class); - - default List convertList(List list, - Map userMap, - List categoryList) { - Map categoryMap = convertMap(categoryList, CrmProductCategoryDO::getId); - return CollectionUtils.convertList(list, - product -> convert(product, userMap, categoryMap.get(product.getCategoryId()))); - } - - default CrmProductRespVO convert(CrmProductDO product, - Map userMap, CrmProductCategoryDO category) { - CrmProductRespVO productVO = BeanUtils.toBean(product, CrmProductRespVO.class); - Optional.ofNullable(category).ifPresent(c -> productVO.setCategoryName(c.getName())); - MapUtils.findAndThen(userMap, productVO.getOwnerUserId(), user -> productVO.setOwnerUserName(user.getNickname())); - MapUtils.findAndThen(userMap, Long.valueOf(productVO.getCreator()), user -> productVO.setCreatorName(user.getNickname())); - return productVO; - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessDO.java index 3a543712b..803f37a38 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessDO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessDO.java @@ -8,10 +8,11 @@ import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; +import java.math.BigDecimal; import java.time.LocalDateTime; /** - * 商机 DO + * CRM 商机 DO * * @author ljlleo */ @@ -26,7 +27,7 @@ import java.time.LocalDateTime; public class CrmBusinessDO extends BaseDO { /** - * 主键 + * 编号 */ @TableId private Long id; @@ -34,6 +35,33 @@ public class CrmBusinessDO extends BaseDO { * 商机名称 */ private String name; + /** + * 客户编号 + * + * 关联 {@link CrmCustomerDO#getId()} + */ + private Long customerId; + + /** + * 跟进状态 + */ + private Boolean followUpStatus; + /** + * 最后跟进时间 + */ + private LocalDateTime contactLastTime; + /** + * 下次联系时间 + */ + private LocalDateTime contactNextTime; + + /** + * 负责人的用户编号 + * + * 关联 AdminUserDO 的 id 字段 + */ + private Long ownerUserId; + /** * 商机状态类型编号 * @@ -46,39 +74,6 @@ public class CrmBusinessDO extends BaseDO { * 关联 {@link CrmBusinessStatusDO#getId()} */ private Long statusId; - /** - * 下次联系时间 - */ - private LocalDateTime contactNextTime; - /** - * 客户编号 - * - * TODO @ljileo:这个字段,后续要写下关联的实体哈 - * 关联 {@link CrmCustomerDO#getId()} - */ - private Long customerId; - /** - * 预计成交日期 - */ - private LocalDateTime dealTime; - /** - * 商机金额 - * - */ - private Integer price; - /** - * 整单折扣 - * - */ - private Integer discountPercent; - /** - * 产品总金额,单位:分 - */ - private Integer productPrice; - /** - * 备注 - */ - private String remark; /** * 结束状态 * @@ -89,20 +84,28 @@ public class CrmBusinessDO extends BaseDO { * 结束时的备注 */ private String endRemark; - /** - * 最后跟进时间 - */ - private LocalDateTime contactLastTime; - /** - * 跟进状态 - */ - private Boolean followUpStatus; /** - * 负责人的用户编号 - * - * 关联 AdminUserDO 的 id 字段 + * 预计成交日期 */ - private Long ownerUserId; + private LocalDateTime dealTime; + /** + * 产品总金额,单位:元 + * + * productPrice = ∑({@link CrmBusinessProductDO#getTotalPrice()}) + */ + private BigDecimal totalProductPrice; + /** + * 整单折扣,百分比 + */ + private BigDecimal discountPercent; + /** + * 商机总金额,单位:元 + */ + private BigDecimal totalPrice; + /** + * 备注 + */ + private String remark; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessProductDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessProductDO.java index 79d6a2a7b..6adc7e42e 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessProductDO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessProductDO.java @@ -7,9 +7,13 @@ import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; +import java.math.BigDecimal; + /** * 商机产品关联表 DO * + * CrmBusinessDO : CrmBusinessProductDO = 1 : N + * * @author lzxhqs */ @TableName("crm_business_product") @@ -40,24 +44,24 @@ public class CrmBusinessProductDO extends BaseDO { */ private Long productId; /** - * 产品单价 + * 产品单价,单位:元 + * + * 冗余 {@link CrmProductDO#getPrice()} */ - private Integer price; + private BigDecimal productPrice; /** - * 销售价格, 单位:分 + * 合同价格, 单位:元 */ - private Integer salesPrice; + private BigDecimal businessPrice; /** * 数量 */ - private Integer count; + private BigDecimal count; /** - * 折扣 + * 总计价格,单位:元 + * + * totalPrice = businessPrice * count */ - private Integer discountPercent; - /** - * 总计价格(折扣后价格) - */ - private Integer totalPrice; + private BigDecimal totalPrice; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/clue/CrmClueDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/clue/CrmClueDO.java index 48e600be6..3af6feec4 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/clue/CrmClueDO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/clue/CrmClueDO.java @@ -11,7 +11,7 @@ import lombok.*; import java.time.LocalDateTime; /** - * 线索 DO + * CRM 线索 DO * * @author Wanwan */ diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/product/CrmProductDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/product/CrmProductDO.java index a3c56ccc9..caeeb53d2 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/product/CrmProductDO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/product/CrmProductDO.java @@ -8,6 +8,8 @@ import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; +import java.math.BigDecimal; + /** * CRM 产品 DO * @@ -43,9 +45,9 @@ public class CrmProductDO extends BaseDO { */ private Integer unit; /** - * 价格,单位:分 + * 价格,单位:元 */ - private Integer price; + private BigDecimal price; /** * 状态 * diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/package-info.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/package-info.java deleted file mode 100644 index 72863e1f4..000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * 商机(销售机会) - */ -package cn.iocoder.yudao.module.crm.dal.mysql.business; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/package-info.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/package-info.java deleted file mode 100644 index 6cb7d4be2..000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * 联系人 - */ -package cn.iocoder.yudao.module.crm.dal.mysql.contact; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/product/CrmProductMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/product/CrmProductMapper.java index 30a07eec2..4d1d61809 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/product/CrmProductMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/product/CrmProductMapper.java @@ -5,10 +5,10 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductPageReqVO; import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; -import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; -import cn.iocoder.yudao.module.crm.util.CrmQueryWrapperUtils; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + /** * CRM 产品 Mapper * @@ -17,21 +17,23 @@ import org.apache.ibatis.annotations.Mapper; @Mapper public interface CrmProductMapper extends BaseMapperX { - default PageResult selectPage(CrmProductPageReqVO reqVO, Long userId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 拼接数据权限的查询条件 - CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_PRODUCT.getType(), - CrmProductDO::getId, userId, null, Boolean.FALSE); - // 拼接自身的查询条件 - query.selectAll(CrmProductDO.class) + default PageResult selectPage(CrmProductPageReqVO reqVO) { + return selectPage(reqVO, new MPJLambdaWrapperX() .likeIfPresent(CrmProductDO::getName, reqVO.getName()) .eqIfPresent(CrmProductDO::getStatus, reqVO.getStatus()) - .orderByDesc(CrmProductDO::getId); - return selectJoinPage(reqVO, CrmProductDO.class, query); + .orderByDesc(CrmProductDO::getId)); } default CrmProductDO selectByNo(String no) { return selectOne(CrmProductDO::getNo, no); } + default Long selectCountByCategoryId(Long categoryId) { + return selectCount(CrmProductDO::getCategoryId, categoryId); + } + + default List selectListByStatus(Integer status) { + return selectList(CrmProductDO::getStatus, status); + } + } 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 683070d02..c7dba0101 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 @@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusi import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessSaveReqVO; import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessTransferReqVO; import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO; 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.service.business.bo.CrmBusinessUpdateProductReqBO; @@ -90,6 +91,14 @@ public interface CrmBusinessService { */ List getBusinessList(Collection ids); + /** + * 获得指定商机编号的产品列表 + * + * @param businessId 商机编号 + * @return 商机产品列表 + */ + List getBusinessProductListByBusinessId(Long businessId); + /** * 获得商机分页 * 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 535578fd2..15dd00ee2 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 @@ -2,9 +2,7 @@ package cn.iocoder.yudao.module.crm.service.business; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil; -import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessPageReqVO; @@ -14,7 +12,6 @@ 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.CrmBusinessProductDO; import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactBusinessDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessMapper; import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessProductMapper; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; @@ -36,14 +33,14 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; +import java.math.BigDecimal; import java.util.Collection; import java.util.List; -import java.util.Map; -import java.util.Set; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.BUSINESS_CONTRACT_EXISTS; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.BUSINESS_NOT_EXISTS; import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; /** @@ -75,27 +72,29 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_CREATE_SUB_TYPE, bizNo = "{{#business.id}}", success = CRM_BUSINESS_CREATE_SUCCESS) public Long createBusiness(CrmBusinessSaveReqVO createReqVO, Long userId) { - createReqVO.setId(null); - // 1. 插入商机 + // 1.1 校验产品项的有效性 + List businessProducts = validateBusinessProducts(createReqVO.getProducts()); + // 1.2 TODO 芋艿:校验关联字 + + // 2.1 插入商机 CrmBusinessDO business = BeanUtils.toBean(createReqVO, CrmBusinessDO.class).setOwnerUserId(userId); + calculateTotalPrice(business, businessProducts); businessMapper.insert(business); - // 1.2 插入商机关联商品 - if (CollUtil.isNotEmpty(createReqVO.getProductItems())) { // 如果有的话 - List productList = buildBusinessProductList(createReqVO.getProductItems(), business.getId()); - businessProductMapper.insertBatch(productList); - // 更新合同商品总金额 - businessMapper.updateById(new CrmBusinessDO().setId(business.getId()).setProductPrice( - getSumValue(productList, CrmBusinessProductDO::getTotalPrice, Integer::sum))); + // 2.2 插入商机关联商品 + if (CollUtil.isNotEmpty(businessProducts)) { + businessProducts.forEach(item -> item.setBusinessId(business.getId())); + businessProductMapper.insertBatch(businessProducts); } + // TODO @puhui999:在联系人的详情页,如果直接【新建商机】,则需要关联下。这里要搞个 CrmContactBusinessDO 表 createContactBusiness(business.getId(), createReqVO.getContactId()); - // 2. 创建数据权限 + // 3. 创建数据权限 // 设置当前操作的人为负责人 permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_BUSINESS.getType()) .setBizId(business.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); - // 3. 记录操作日志上下文 + // 4. 记录操作日志上下文 LogRecordContext.putVariable("business", business); return business.getId(); } @@ -114,15 +113,18 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { success = CRM_BUSINESS_UPDATE_SUCCESS) @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) public void updateBusiness(CrmBusinessSaveReqVO updateReqVO) { - // 1. 校验存在 + // 1.1 校验存在 CrmBusinessDO oldBusiness = validateBusinessExists(updateReqVO.getId()); + // 1.2 校验产品项的有效性 + List businessProducts = validateBusinessProducts(updateReqVO.getProducts()); + // 1.3 TODO 芋艿:校验关联字 // 2.1 更新商机 CrmBusinessDO updateObj = BeanUtils.toBean(updateReqVO, CrmBusinessDO.class); + calculateTotalPrice(updateObj, businessProducts); businessMapper.updateById(updateObj); // 2.2 更新商机关联商品 - List productList = buildBusinessProductList(updateReqVO.getProductItems(), updateObj.getId()); - updateBusinessProduct(productList, updateObj.getId()); + updateBusinessProduct(updateObj.getId(), businessProducts); // TODO @商机待定:如果状态发生变化,插入商机状态变更记录表 // 3. 记录操作日志上下文 @@ -130,6 +132,37 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { LogRecordContext.putVariable("businessName", oldBusiness.getName()); } + private void updateBusinessProduct(Long id, List newList) { + List oldList = businessProductMapper.selectListByBusinessId(id); + List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); + if (CollUtil.isNotEmpty(diffList.get(0))) { + diffList.get(0).forEach(o -> o.setBusinessId(id)); + businessProductMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + businessProductMapper.updateBatch(diffList.get(1)); + } + if (CollUtil.isNotEmpty(diffList.get(2))) { + businessProductMapper.deleteBatchIds(convertSet(diffList.get(2), CrmBusinessProductDO::getId)); + } + } + + private List validateBusinessProducts(List list) { + // 1. 校验产品存在 + productService.validProductList(convertSet(list, CrmBusinessSaveReqVO.Product::getProductId)); + // 2. 转化为 CrmBusinessProductDO 列表 + return convertList(list, o -> BeanUtils.toBean(o, CrmBusinessProductDO.class, item -> { + item.setTotalPrice(MoneyUtils.priceMultiply(item.getBusinessPrice(), item.getCount())); + })); + } + + private void calculateTotalPrice(CrmBusinessDO business, List businessProducts) { + business.setTotalProductPrice(getSumValue(businessProducts, CrmBusinessProductDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)); + BigDecimal discountPrice = MoneyUtils.priceMultiplyPercent(business.getTotalProductPrice(), business.getDiscountPercent()); + business.setTotalPrice(business.getTotalProductPrice().subtract(discountPrice)); + } + @Override public void updateBusinessFollowUpBatch(List updateFollowUpReqBOList) { businessMapper.updateBatch(CrmBusinessConvert.INSTANCE.convertList(updateFollowUpReqBOList)); @@ -155,44 +188,6 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { LogRecordContext.putVariable("businessName", business.getName()); } - private void updateBusinessProduct(List newProductList, Long businessId) { - List oldProducts = businessProductMapper.selectListByBusinessId(businessId); - List> diffList = CollectionUtils.diffList(oldProducts, newProductList, (oldValue, newValue) -> { - boolean condition = ObjectUtil.equal(oldValue.getProductId(), newValue.getProductId()); - if (condition) { - newValue.setId(oldValue.getId()); // 更新需要原始编号 - } - return condition; - }); - if (CollUtil.isNotEmpty(diffList.get(0))) { - businessProductMapper.insertBatch(diffList.get(0)); - } - if (CollUtil.isNotEmpty(diffList.get(1))) { - businessProductMapper.updateBatch(diffList.get(1)); - } - if (CollUtil.isNotEmpty(diffList.get(2))) { - businessProductMapper.deleteBatchIds(convertSet(diffList.get(2), CrmBusinessProductDO::getId)); - } - } - - private List buildBusinessProductList(List productItems, - Long businessId) { - // 校验商品存在 - Set productIds = convertSet(productItems, CrmBusinessSaveReqVO.CrmBusinessProductItem::getId); - List productList = productService.getProductList(productIds); - if (CollUtil.isEmpty(productIds) || productList.size() != productIds.size()) { - throw exception(PRODUCT_NOT_EXISTS); - } - Map productMap = convertMap(productList, CrmProductDO::getId); - return convertList(productItems, productItem -> { - CrmProductDO product = productMap.get(productItem.getId()); - return BeanUtils.toBean(product, CrmBusinessProductDO.class) - .setId(null).setProductId(productItem.getId()).setBusinessId(businessId) - .setCount(productItem.getCount()).setDiscountPercent(productItem.getDiscountPercent()) - .setTotalPrice(MoneyUtils.calculator(product.getPrice(), productItem.getCount(), productItem.getDiscountPercent())); - }); - } - /** * 删除校验合同是关联合同 * @@ -235,10 +230,10 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { @Override public void updateBusinessProduct(CrmBusinessUpdateProductReqBO updateProductReqBO) { - // 更新商机关联商品 - List productList = buildBusinessProductList( - BeanUtils.toBean(updateProductReqBO.getProductItems(), CrmBusinessSaveReqVO.CrmBusinessProductItem.class), updateProductReqBO.getId()); - updateBusinessProduct(productList, updateProductReqBO.getId()); + // 更新商机关联商品 TODO yunai +// List productList = buildBusinessProductList( +// BeanUtils.toBean(updateProductReqBO.getProductItems(), CrmBusinessSaveReqVO.Product.class), updateProductReqBO.getId()); +// updateBusinessProduct(productList, updateProductReqBO.getId()); } //======================= 查询相关 ======================= @@ -265,6 +260,11 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { return businessMapper.selectBatchIds(ids); } + @Override + public List getBusinessProductListByBusinessId(Long businessId) { + return businessProductMapper.selectListByBusinessId(businessId); + } + @Override public PageResult getBusinessPage(CrmBusinessPageReqVO pageReqVO, Long userId) { return businessMapper.selectPage(pageReqVO, userId); 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 a2fc2d18d..d9128b429 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 @@ -5,11 +5,13 @@ import cn.iocoder.yudao.module.crm.controller.admin.business.vo.status.CrmBusine import cn.iocoder.yudao.module.crm.controller.admin.business.vo.status.CrmBusinessStatusQueryVO; import cn.iocoder.yudao.module.crm.controller.admin.business.vo.status.CrmBusinessStatusSaveReqVO; import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; - import jakarta.validation.Valid; import java.util.Collection; import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; /** * 商机状态 Service 接口 @@ -74,4 +76,14 @@ public interface CrmBusinessStatusService { */ List getBusinessStatusList(Collection ids); + /** + * 获得商机状态 Map + * + * @param ids 编号数组 + * @return 商机状态 Map + */ + default Map getBusinessStatusMap(Collection ids) { + return convertMap(getBusinessStatusList(ids), CrmBusinessStatusDO::getId); + } + } 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 2e49e99d7..b838fdc6f 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 @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.crm.service.business; +import cn.hutool.core.collection.CollUtil; 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.status.CrmBusinessStatusPageReqVO; @@ -13,6 +14,7 @@ import org.springframework.validation.annotation.Validated; import jakarta.annotation.Resource; import java.util.Collection; +import java.util.Collections; import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; @@ -80,6 +82,9 @@ public class CrmBusinessStatusServiceImpl implements CrmBusinessStatusService { @Override public List getBusinessStatusList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } 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 20509994e..a48ff0503 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 @@ -9,6 +9,9 @@ import jakarta.validation.Valid; import java.util.Collection; import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; /** * 商机状态类型 Service 接口 @@ -72,4 +75,14 @@ public interface CrmBusinessStatusTypeService { */ List getBusinessStatusTypeList(Collection ids); + /** + * 获得商机状态类型 Map + * + * @param ids 编号数组 + * @return 商机状态类型 Map + */ + default Map getBusinessStatusTypeMap(Collection ids) { + return convertMap(getBusinessStatusTypeList(ids), CrmBusinessStatusTypeDO::getId); + } + } 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 d9845976b..85d30e8ce 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 @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.crm.service.business; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.type.CrmBusinessStatusTypePageReqVO; import cn.iocoder.yudao.module.crm.controller.admin.business.vo.type.CrmBusinessStatusTypeQueryVO; import cn.iocoder.yudao.module.crm.controller.admin.business.vo.type.CrmBusinessStatusTypeSaveReqVO; @@ -11,19 +10,18 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusTypeDO; import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessStatusMapper; import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessStatusTypeMapper; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; -import jakarta.annotation.Resource; - import java.util.Collection; +import java.util.Collections; import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.BUSINESS_STATUS_TYPE_NOT_EXISTS; import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.BUSINESS_STATUS_TYPE_NAME_EXISTS; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.BUSINESS_STATUS_TYPE_NOT_EXISTS; /** * 商机状态类型 Service 实现类 @@ -126,6 +124,9 @@ public class CrmBusinessStatusTypeServiceImpl implements CrmBusinessStatusTypeSe @Override public List getBusinessStatusTypeList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } return businessStatusTypeMapper.selectBatchIds(ids); } 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 71b9446e4..cdd888544 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 @@ -184,7 +184,8 @@ public class CrmContractServiceImpl implements CrmContractService { return BeanUtils.toBean(product, CrmContractProductDO.class) .setId(null).setProductId(productItem.getId()).setContractId(contractId) .setCount(productItem.getCount()).setDiscountPercent(productItem.getDiscountPercent()) - .setTotalPrice(MoneyUtils.calculator(product.getPrice(), productItem.getCount(), productItem.getDiscountPercent())); + // TODO 芋艿:这里临时注释掉 + .setTotalPrice(MoneyUtils.calculator(null, productItem.getCount(), productItem.getDiscountPercent())); }); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryService.java index 56974da11..c68c0cf77 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryService.java @@ -3,10 +3,13 @@ package cn.iocoder.yudao.module.crm.service.product; import cn.iocoder.yudao.module.crm.controller.admin.product.vo.category.CrmProductCategoryCreateReqVO; import cn.iocoder.yudao.module.crm.controller.admin.product.vo.category.CrmProductCategoryListReqVO; import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductCategoryDO; - import jakarta.validation.Valid; + import java.util.Collection; import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; /** * CRM 产品分类 Service 接口 @@ -61,4 +64,14 @@ public interface CrmProductCategoryService { */ List getProductCategoryList(Collection ids); + /** + * 获得产品分类 Map + * + * @param ids 编号数组 + * @return 产品分类 Map + */ + default Map getProductCategoryMap(Collection ids) { + return convertMap(getProductCategoryList(ids), CrmProductCategoryDO::getId); + } + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductService.java index 6d2dd4943..9379734ef 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductService.java @@ -8,6 +8,9 @@ import jakarta.validation.Valid; import java.util.Collection; import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; /** * CRM 产品 Service 接口 @@ -54,28 +57,46 @@ public interface CrmProductService { */ List getProductList(Collection ids); + /** + * 获得产品 Map + * + * @param ids 编号 + * @return 产品 Map + */ + default Map getProductMap(Collection ids) { + return convertMap(getProductList(ids), CrmProductDO::getId); + } + /** * 获得产品分页 * * @param pageReqVO 分页查询 * @return 产品分页 */ - PageResult getProductPage(CrmProductPageReqVO pageReqVO, Long userId); + PageResult getProductPage(CrmProductPageReqVO pageReqVO); /** - * 获得产品 + * 获得产品数量 * * @param categoryId 分类编号 * @return 产品 */ - CrmProductDO getProductByCategoryId(Long categoryId); + Long getProductByCategoryId(Long categoryId); /** - * 获得产品列表 + * 获得指定状态的产品列表 * - * @param ids 产品编号 + * @param status 状态 * @return 产品列表 */ - List getProductListByIds(Collection ids); + List getProductListByStatus(Integer status); + + /** + * 校验产品们的有效性 + * + * @param ids 编号数组 + * @return 产品列表 + */ + List validProductList(Collection ids); } 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 95205524e..c44bc6b9e 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 @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.crm.service.product; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.collection.ListUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 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.product.vo.product.CrmProductPageReqVO; @@ -15,7 +15,6 @@ import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPerm import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.mzt.logapi.context.LogRecordContext; import com.mzt.logapi.service.impl.DiffParseFunction; import com.mzt.logapi.starter.annotation.LogRecord; @@ -27,8 +26,10 @@ import org.springframework.validation.annotation.Validated; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; @@ -138,25 +139,41 @@ public class CrmProductServiceImpl implements CrmProductService { } @Override - public List getProductList(Collection ids) { + public PageResult getProductPage(CrmProductPageReqVO pageReqVO) { + return productMapper.selectPage(pageReqVO); + } + + @Override + public Long getProductByCategoryId(Long categoryId) { + return productMapper.selectCountByCategoryId(categoryId); + } + + @Override + public List getProductListByStatus(Integer status) { + return productMapper.selectListByStatus(status); + } + + @Override + public List validProductList(Collection ids) { if (CollUtil.isEmpty(ids)) { - return ListUtil.empty(); + return Collections.emptyList(); } - return productMapper.selectBatchIds(ids); + List list = productMapper.selectBatchIds(ids); + Map productMap = convertMap(list, CrmProductDO::getId); + for (Long id : ids) { + CrmProductDO product = productMap.get(id); + if (productMap.get(id) == null) { + throw exception(PRODUCT_NOT_EXISTS); + } + if (CommonStatusEnum.isDisable(product.getStatus())) { + throw exception(PRODUCT_NOT_ENABLE, product.getName()); + } + } + return list; } @Override - public PageResult getProductPage(CrmProductPageReqVO pageReqVO, Long userId) { - return productMapper.selectPage(pageReqVO, userId); - } - - @Override - public CrmProductDO getProductByCategoryId(Long categoryId) { - return productMapper.selectOne(new LambdaQueryWrapper().eq(CrmProductDO::getCategoryId, categoryId)); - } - - @Override - public List getProductListByIds(Collection ids) { + public List getProductList(Collection ids) { if (CollUtil.isEmpty(ids)) { return Collections.emptyList(); }