From bee6f41211ce9702aef054e4577d059f9faedd9e Mon Sep 17 00:00:00 2001 From: ljlleo Date: Fri, 20 Oct 2023 16:01:54 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=95=86=E6=9C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/crm/enums/ErrorCodeConstants.java | 3 + .../admin/business/CrmBusinessController.java | 99 ++++++ .../admin/business/vo/CrmBusinessBaseVO.java | 78 +++++ .../business/vo/CrmBusinessCreateReqVO.java | 14 + .../admin/business/vo/CrmBusinessExcelVO.java | 82 +++++ .../business/vo/CrmBusinessExportReqVO.java | 74 +++++ .../business/vo/CrmBusinessPageReqVO.java | 79 +++++ .../admin/business/vo/CrmBusinessRespVO.java | 19 ++ .../business/vo/CrmBusinessUpdateReqVO.java | 18 ++ .../convert/business/CrmBusinessConvert.java | 34 +++ .../dataobject/business/CrmBusinessDO.java | 101 +++++++ .../dal/mysql/business/CrmBusinessMapper.java | 67 +++++ .../service/business/CrmBusinessService.java | 75 +++++ .../business/CrmBusinessServiceImpl.java | 90 ++++++ .../mapper/business/CrmBusinessMapper.xml | 12 + .../business/CrmBusinessServiceImplTest.java | 283 ++++++++++++++++++ 16 files changed, 1128 insertions(+) create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessBaseVO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessCreateReqVO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessExcelVO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessExportReqVO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessPageReqVO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessRespVO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessUpdateReqVO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/business/CrmBusinessConvert.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessDO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/business/CrmBusinessMapper.xml create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/test/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImplTest.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 3538b16ee..66f2abc1f 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 @@ -15,4 +15,7 @@ public interface ErrorCodeConstants { // TODO @wanwan:要单独一个分段噢 ErrorCode CLUE_NOT_EXISTS = new ErrorCode(1_020_000_001, "线索不存在"); + // ========== 商机管理 1-020-001-000 ========== + ErrorCode BUSINESS_NOT_EXISTS = new ErrorCode(1_020_001_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 new file mode 100644 index 000000000..85cc48f79 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java @@ -0,0 +1,99 @@ +package cn.iocoder.yudao.module.crm.controller.admin.business; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +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.*; +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.service.business.CrmBusinessService; +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.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; + +@Tag(name = "管理后台 - 商机") +@RestController +@RequestMapping("/crm/business") +@Validated +public class CrmBusinessController { + + @Resource + private CrmBusinessService businessService; + + @PostMapping("/create") + @Operation(summary = "创建商机") + @PreAuthorize("@ss.hasPermission('crm:business:create')") + public CommonResult createBusiness(@Valid @RequestBody CrmBusinessCreateReqVO createReqVO) { + return success(businessService.createBusiness(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新商机") + @PreAuthorize("@ss.hasPermission('crm:business:update')") + public CommonResult updateBusiness(@Valid @RequestBody CrmBusinessUpdateReqVO updateReqVO) { + businessService.updateBusiness(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除商机") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('crm:business:delete')") + public CommonResult deleteBusiness(@RequestParam("id") Long id) { + businessService.deleteBusiness(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得商机") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('crm:business:query')") + public CommonResult getBusiness(@RequestParam("id") Long id) { + CrmBusinessDO business = businessService.getBusiness(id); + return success(CrmBusinessConvert.INSTANCE.convert(business)); + } + + @GetMapping("/list") + @Operation(summary = "获得商机列表") + @Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048") + @PreAuthorize("@ss.hasPermission('crm:business:query')") + public CommonResult> getBusinessList(@RequestParam("ids") Collection ids) { + List list = businessService.getBusinessList(ids); + return success(CrmBusinessConvert.INSTANCE.convertList(list)); + } + + @GetMapping("/page") + @Operation(summary = "获得商机分页") + @PreAuthorize("@ss.hasPermission('crm:business:query')") + public CommonResult> getBusinessPage(@Valid CrmBusinessPageReqVO pageVO) { + PageResult pageResult = businessService.getBusinessPage(pageVO); + return success(CrmBusinessConvert.INSTANCE.convertPage(pageResult)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出商机 Excel") + @PreAuthorize("@ss.hasPermission('crm:business:export')") + @OperateLog(type = EXPORT) + public void exportBusinessExcel(@Valid CrmBusinessExportReqVO exportReqVO, + HttpServletResponse response) throws IOException { + List list = businessService.getBusinessList(exportReqVO); + // 导出 Excel + List datas = CrmBusinessConvert.INSTANCE.convertList02(list); + ExcelUtils.write(response, "商机.xls", "数据", CrmBusinessExcelVO.class, datas); + } + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessBaseVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessBaseVO.java new file mode 100644 index 000000000..7e32feea0 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessBaseVO.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.crm.controller.admin.business.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +/** + * 商机 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class CrmBusinessBaseVO { + + @Schema(description = "商机名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @NotNull(message = "商机名称不能为空") + private String name; + + @Schema(description = "商机状态类型编号", example = "25714") + @NotNull(message = "商机状态类型不能为空") + private Long statusTypeId; + + @Schema(description = "商机状态编号", 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 BigDecimal price; + + @Schema(description = "整单折扣") + private BigDecimal discountPercent; + + @Schema(description = "产品总金额", example = "12025") + private BigDecimal productPrice; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "负责人的用户编号", example = "25562") + private Long ownerUserId; + + @Schema(description = "只读权限的用户编号数组", requiredMode = Schema.RequiredMode.REQUIRED) + private String roUserIds; + + @Schema(description = "读写权限的用户编号数组", requiredMode = Schema.RequiredMode.REQUIRED) + private String rwUserIds; + + @Schema(description = "1赢单2输单3无效", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer endStatus; + + @Schema(description = "结束时的备注", example = "你说的对") + private String endRemark; + + @Schema(description = "最后跟进时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime contactLastTime; + + @Schema(description = "跟进状态", example = "1") + 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/CrmBusinessCreateReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessCreateReqVO.java new file mode 100644 index 000000000..a03540cc6 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessCreateReqVO.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.crm.controller.admin.business.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import javax.validation.constraints.*; + +@Schema(description = "管理后台 - 商机创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CrmBusinessCreateReqVO extends CrmBusinessBaseVO { + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessExcelVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessExcelVO.java new file mode 100644 index 000000000..087deafb0 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessExcelVO.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.crm.controller.admin.business.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import java.math.BigDecimal; +import java.math.BigDecimal; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import java.time.LocalDateTime; + +import com.alibaba.excel.annotation.ExcelProperty; + +/** + * 商机 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 String roUserIds; + + @ExcelProperty("读写权限的用户编号数组") + private String 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/CrmBusinessExportReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessExportReqVO.java new file mode 100644 index 000000000..a44283112 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessExportReqVO.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.crm.controller.admin.business.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 商机 Excel 导出 Request VO,参数和 CrmBusinessPageReqVO 是一致的") +@Data +public class CrmBusinessExportReqVO { + + @Schema(description = "商机名称", example = "李四") + private String name; + + @Schema(description = "商机状态类型编号", example = "25714") + private Long statusTypeId; + + @Schema(description = "商机状态编号", example = "30320") + private Long statusId; + + @Schema(description = "下次联系时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] contactNextTime; + + @Schema(description = "客户编号", example = "10299") + private Long customerId; + + @Schema(description = "预计成交日期") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] dealTime; + + @Schema(description = "商机金额", example = "12371") + private BigDecimal price; + + @Schema(description = "整单折扣") + private BigDecimal discountPercent; + + @Schema(description = "产品总金额", example = "12025") + private BigDecimal productPrice; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "负责人的用户编号", example = "25562") + private Long ownerUserId; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "只读权限的用户编号数组") + private String roUserIds; + + @Schema(description = "读写权限的用户编号数组") + private String rwUserIds; + + @Schema(description = "1赢单2输单3无效", example = "1") + private Integer endStatus; + + @Schema(description = "结束时的备注", example = "你说的对") + private String endRemark; + + @Schema(description = "最后跟进时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] contactLastTime; + + @Schema(description = "跟进状态", example = "1") + 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/CrmBusinessPageReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessPageReqVO.java new file mode 100644 index 000000000..636661a9f --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessPageReqVO.java @@ -0,0 +1,79 @@ +package cn.iocoder.yudao.module.crm.controller.admin.business.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.math.BigDecimal; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 商机分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CrmBusinessPageReqVO extends PageParam { + + @Schema(description = "商机名称", example = "李四") + private String name; + + @Schema(description = "商机状态类型编号", example = "25714") + private Long statusTypeId; + + @Schema(description = "商机状态编号", example = "30320") + private Long statusId; + + @Schema(description = "下次联系时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] contactNextTime; + + @Schema(description = "客户编号", example = "10299") + private Long customerId; + + @Schema(description = "预计成交日期") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] dealTime; + + @Schema(description = "商机金额", example = "12371") + private BigDecimal price; + + @Schema(description = "整单折扣") + private BigDecimal discountPercent; + + @Schema(description = "产品总金额", example = "12025") + private BigDecimal productPrice; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "负责人的用户编号", example = "25562") + private Long ownerUserId; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "只读权限的用户编号数组") + private String roUserIds; + + @Schema(description = "读写权限的用户编号数组") + private String rwUserIds; + + @Schema(description = "1赢单2输单3无效", example = "1") + private Integer endStatus; + + @Schema(description = "结束时的备注", example = "你说的对") + private String endRemark; + + @Schema(description = "最后跟进时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] contactLastTime; + + @Schema(description = "跟进状态", example = "1") + 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/CrmBusinessRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessRespVO.java new file mode 100644 index 000000000..672f99ec3 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.crm.controller.admin.business.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 商机 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CrmBusinessRespVO extends CrmBusinessBaseVO { + + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "32129") + private Long id; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessUpdateReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessUpdateReqVO.java new file mode 100644 index 000000000..8922ec99b --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessUpdateReqVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.crm.controller.admin.business.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import javax.validation.constraints.*; + +@Schema(description = "管理后台 - 商机更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CrmBusinessUpdateReqVO extends CrmBusinessBaseVO { + + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "32129") + @NotNull(message = "主键不能为空") + private Long id; + +} 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 new file mode 100644 index 000000000..aa03ce0f0 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/business/CrmBusinessConvert.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.crm.convert.business; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.*; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; + +/** + * 商机 Convert + * + * @author ljlleo + */ +@Mapper +public interface CrmBusinessConvert { + + CrmBusinessConvert INSTANCE = Mappers.getMapper(CrmBusinessConvert.class); + + CrmBusinessDO convert(CrmBusinessCreateReqVO bean); + + CrmBusinessDO convert(CrmBusinessUpdateReqVO bean); + + CrmBusinessRespVO convert(CrmBusinessDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + List convertList02(List list); + +} 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 new file mode 100644 index 000000000..620fb492e --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessDO.java @@ -0,0 +1,101 @@ +package cn.iocoder.yudao.module.crm.dal.dataobject.business; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * 商机 DO + * + * @author ljlleo + */ +@TableName("crm_business") +@KeySequence("crm_business_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CrmBusinessDO extends BaseDO { + + /** + * 主键 + */ + @TableId + private Long id; + /** + * 商机名称 + */ + private String name; + /** + * 商机状态类型编号 + */ + private Long statusTypeId; + /** + * 商机状态编号 + */ + private Long statusId; + /** + * 下次联系时间 + */ + private LocalDateTime contactNextTime; + /** + * 客户编号 + */ + private Long customerId; + /** + * 预计成交日期 + */ + private LocalDateTime dealTime; + /** + * 商机金额 + */ + private BigDecimal price; + /** + * 整单折扣 + */ + private BigDecimal discountPercent; + /** + * 产品总金额 + */ + private BigDecimal productPrice; + /** + * 备注 + */ + private String remark; + /** + * 负责人的用户编号 + */ + private Long ownerUserId; + /** + * 只读权限的用户编号数组 + */ + private String roUserIds; + /** + * 读写权限的用户编号数组 + */ + private String rwUserIds; + /** + * 1赢单2输单3无效 + */ + private Integer endStatus; + /** + * 结束时的备注 + */ + private String endRemark; + /** + * 最后跟进时间 + */ + private LocalDateTime contactLastTime; + /** + * 跟进状态 + */ + private Integer followUpStatus; + +} 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 new file mode 100644 index 000000000..aadec8517 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.business; + +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.business.vo.CrmBusinessExportReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.CrmBusinessPageReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 商机 Mapper + * + * @author ljlleo + */ +@Mapper +public interface CrmBusinessMapper extends BaseMapperX { + + default PageResult selectPage(CrmBusinessPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(CrmBusinessDO::getName, reqVO.getName()) + .eqIfPresent(CrmBusinessDO::getStatusTypeId, reqVO.getStatusTypeId()) + .eqIfPresent(CrmBusinessDO::getStatusId, reqVO.getStatusId()) + .betweenIfPresent(CrmBusinessDO::getContactNextTime, reqVO.getContactNextTime()) + .eqIfPresent(CrmBusinessDO::getCustomerId, reqVO.getCustomerId()) + .betweenIfPresent(CrmBusinessDO::getDealTime, reqVO.getDealTime()) + .eqIfPresent(CrmBusinessDO::getPrice, reqVO.getPrice()) + .eqIfPresent(CrmBusinessDO::getDiscountPercent, reqVO.getDiscountPercent()) + .eqIfPresent(CrmBusinessDO::getProductPrice, reqVO.getProductPrice()) + .eqIfPresent(CrmBusinessDO::getRemark, reqVO.getRemark()) + .eqIfPresent(CrmBusinessDO::getOwnerUserId, reqVO.getOwnerUserId()) + .betweenIfPresent(CrmBusinessDO::getCreateTime, reqVO.getCreateTime()) + .eqIfPresent(CrmBusinessDO::getRoUserIds, reqVO.getRoUserIds()) + .eqIfPresent(CrmBusinessDO::getRwUserIds, reqVO.getRwUserIds()) + .eqIfPresent(CrmBusinessDO::getEndStatus, reqVO.getEndStatus()) + .eqIfPresent(CrmBusinessDO::getEndRemark, reqVO.getEndRemark()) + .betweenIfPresent(CrmBusinessDO::getContactLastTime, reqVO.getContactLastTime()) + .eqIfPresent(CrmBusinessDO::getFollowUpStatus, reqVO.getFollowUpStatus()) + .orderByDesc(CrmBusinessDO::getId)); + } + + default List selectList(CrmBusinessExportReqVO reqVO) { + return selectList(new LambdaQueryWrapperX() + .likeIfPresent(CrmBusinessDO::getName, reqVO.getName()) + .eqIfPresent(CrmBusinessDO::getStatusTypeId, reqVO.getStatusTypeId()) + .eqIfPresent(CrmBusinessDO::getStatusId, reqVO.getStatusId()) + .betweenIfPresent(CrmBusinessDO::getContactNextTime, reqVO.getContactNextTime()) + .eqIfPresent(CrmBusinessDO::getCustomerId, reqVO.getCustomerId()) + .betweenIfPresent(CrmBusinessDO::getDealTime, reqVO.getDealTime()) + .eqIfPresent(CrmBusinessDO::getPrice, reqVO.getPrice()) + .eqIfPresent(CrmBusinessDO::getDiscountPercent, reqVO.getDiscountPercent()) + .eqIfPresent(CrmBusinessDO::getProductPrice, reqVO.getProductPrice()) + .eqIfPresent(CrmBusinessDO::getRemark, reqVO.getRemark()) + .eqIfPresent(CrmBusinessDO::getOwnerUserId, reqVO.getOwnerUserId()) + .betweenIfPresent(CrmBusinessDO::getCreateTime, reqVO.getCreateTime()) + .eqIfPresent(CrmBusinessDO::getRoUserIds, reqVO.getRoUserIds()) + .eqIfPresent(CrmBusinessDO::getRwUserIds, reqVO.getRwUserIds()) + .eqIfPresent(CrmBusinessDO::getEndStatus, reqVO.getEndStatus()) + .eqIfPresent(CrmBusinessDO::getEndRemark, reqVO.getEndRemark()) + .betweenIfPresent(CrmBusinessDO::getContactLastTime, reqVO.getContactLastTime()) + .eqIfPresent(CrmBusinessDO::getFollowUpStatus, reqVO.getFollowUpStatus()) + .orderByDesc(CrmBusinessDO::getId)); + } + +} 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 new file mode 100644 index 000000000..4bb352c58 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.module.crm.service.business; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.CrmBusinessCreateReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.CrmBusinessExportReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.CrmBusinessPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.CrmBusinessUpdateReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + +/** + * 商机 Service 接口 + * + * @author ljlleo + */ +public interface CrmBusinessService { + + /** + * 创建商机 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createBusiness(@Valid CrmBusinessCreateReqVO createReqVO); + + /** + * 更新商机 + * + * @param updateReqVO 更新信息 + */ + void updateBusiness(@Valid CrmBusinessUpdateReqVO updateReqVO); + + /** + * 删除商机 + * + * @param id 编号 + */ + void deleteBusiness(Long id); + + /** + * 获得商机 + * + * @param id 编号 + * @return 商机 + */ + CrmBusinessDO getBusiness(Long id); + + /** + * 获得商机列表 + * + * @param ids 编号 + * @return 商机列表 + */ + List getBusinessList(Collection ids); + + /** + * 获得商机分页 + * + * @param pageReqVO 分页查询 + * @return 商机分页 + */ + PageResult getBusinessPage(CrmBusinessPageReqVO pageReqVO); + + /** + * 获得商机列表, 用于 Excel 导出 + * + * @param exportReqVO 查询条件 + * @return 商机列表 + */ + List getBusinessList(CrmBusinessExportReqVO exportReqVO); + +} 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 new file mode 100644 index 000000000..44fa74f80 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java @@ -0,0 +1,90 @@ +package cn.iocoder.yudao.module.crm.service.business; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.CrmBusinessCreateReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.CrmBusinessExportReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.CrmBusinessPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.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.mysql.business.CrmBusinessMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.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.BUSINESS_NOT_EXISTS; + +/** + * 商机 Service 实现类 + * + * @author ljlleo + */ +@Service +@Validated +public class CrmBusinessServiceImpl implements CrmBusinessService { + + @Resource + private CrmBusinessMapper businessMapper; + + @Override + public Long createBusiness(CrmBusinessCreateReqVO createReqVO) { + // 插入 + CrmBusinessDO business = CrmBusinessConvert.INSTANCE.convert(createReqVO); + businessMapper.insert(business); + // 返回 + return business.getId(); + } + + @Override + public void updateBusiness(CrmBusinessUpdateReqVO updateReqVO) { + // 校验存在 + validateBusinessExists(updateReqVO.getId()); + // 更新 + CrmBusinessDO updateObj = CrmBusinessConvert.INSTANCE.convert(updateReqVO); + businessMapper.updateById(updateObj); + } + + @Override + public void deleteBusiness(Long id) { + // 校验存在 + validateBusinessExists(id); + // 删除 + businessMapper.deleteById(id); + } + + private void validateBusinessExists(Long id) { + if (businessMapper.selectById(id) == null) { + throw exception(BUSINESS_NOT_EXISTS); + } + } + + @Override + public CrmBusinessDO getBusiness(Long id) { + return businessMapper.selectById(id); + } + + @Override + public List getBusinessList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return ListUtil.empty(); + } + return businessMapper.selectBatchIds(ids); + } + + @Override + public PageResult getBusinessPage(CrmBusinessPageReqVO pageReqVO) { + return businessMapper.selectPage(pageReqVO); + } + + @Override + public List getBusinessList(CrmBusinessExportReqVO exportReqVO) { + return businessMapper.selectList(exportReqVO); + } + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/business/CrmBusinessMapper.xml b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/business/CrmBusinessMapper.xml new file mode 100644 index 000000000..c35aafec7 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/business/CrmBusinessMapper.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/yudao-module-crm/yudao-module-crm-biz/src/test/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImplTest.java b/yudao-module-crm/yudao-module-crm-biz/src/test/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImplTest.java new file mode 100644 index 000000000..64d3f1e71 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/test/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImplTest.java @@ -0,0 +1,283 @@ +package cn.iocoder.yudao.module.crm.service.business; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.CrmBusinessCreateReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.CrmBusinessExportReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.CrmBusinessPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.CrmBusinessUpdateReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessMapper; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.BUSINESS_NOT_EXISTS; +import static org.junit.jupiter.api.Assertions.*; + +/** + * {@link CrmBusinessServiceImpl} 的单元测试类 + * + * @author ljlleo + */ +@Import(CrmBusinessServiceImpl.class) +public class CrmBusinessServiceImplTest extends BaseDbUnitTest { + + @Resource + private CrmBusinessServiceImpl businessService; + + @Resource + private CrmBusinessMapper businessMapper; + + @Test + public void testCreateBusiness_success() { + // 准备参数 + CrmBusinessCreateReqVO reqVO = randomPojo(CrmBusinessCreateReqVO.class); + + // 调用 + Long businessId = businessService.createBusiness(reqVO); + // 断言 + assertNotNull(businessId); + // 校验记录的属性是否正确 + CrmBusinessDO business = businessMapper.selectById(businessId); + assertPojoEquals(reqVO, business); + } + + @Test + public void testUpdateBusiness_success() { + // mock 数据 + CrmBusinessDO dbBusiness = randomPojo(CrmBusinessDO.class); + businessMapper.insert(dbBusiness);// @Sql: 先插入出一条存在的数据 + // 准备参数 + CrmBusinessUpdateReqVO reqVO = randomPojo(CrmBusinessUpdateReqVO.class, o -> { + o.setId(dbBusiness.getId()); // 设置更新的 ID + }); + + // 调用 + businessService.updateBusiness(reqVO); + // 校验是否更新正确 + CrmBusinessDO business = businessMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, business); + } + + @Test + public void testUpdateBusiness_notExists() { + // 准备参数 + CrmBusinessUpdateReqVO reqVO = randomPojo(CrmBusinessUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> businessService.updateBusiness(reqVO), BUSINESS_NOT_EXISTS); + } + + @Test + public void testDeleteBusiness_success() { + // mock 数据 + CrmBusinessDO dbBusiness = randomPojo(CrmBusinessDO.class); + businessMapper.insert(dbBusiness);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbBusiness.getId(); + + // 调用 + businessService.deleteBusiness(id); + // 校验数据不存在了 + assertNull(businessMapper.selectById(id)); + } + + @Test + public void testDeleteBusiness_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> businessService.deleteBusiness(id), BUSINESS_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetBusinessPage() { + // mock 数据 + CrmBusinessDO dbBusiness = randomPojo(CrmBusinessDO.class, o -> { // 等会查询到 + o.setName(null); + o.setStatusTypeId(null); + o.setStatusId(null); + o.setContactNextTime(null); + o.setCustomerId(null); + o.setDealTime(null); + o.setPrice(null); + o.setDiscountPercent(null); + o.setProductPrice(null); + o.setRemark(null); + o.setOwnerUserId(null); + o.setCreateTime(null); + o.setRoUserIds(null); + o.setRwUserIds(null); + o.setEndStatus(null); + o.setEndRemark(null); + o.setContactLastTime(null); + o.setFollowUpStatus(null); + }); + businessMapper.insert(dbBusiness); + // 测试 name 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setName(null))); + // 测试 statusTypeId 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setStatusTypeId(null))); + // 测试 statusId 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setStatusId(null))); + // 测试 contactNextTime 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setContactNextTime(null))); + // 测试 customerId 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setCustomerId(null))); + // 测试 dealTime 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setDealTime(null))); + // 测试 price 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setPrice(null))); + // 测试 discountPercent 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setDiscountPercent(null))); + // 测试 productPrice 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setProductPrice(null))); + // 测试 remark 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setRemark(null))); + // 测试 ownerUserId 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setOwnerUserId(null))); + // 测试 createTime 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setCreateTime(null))); + // 测试 roUserIds 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setRoUserIds(null))); + // 测试 rwUserIds 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setRwUserIds(null))); + // 测试 endStatus 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setEndStatus(null))); + // 测试 endRemark 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setEndRemark(null))); + // 测试 contactLastTime 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setContactLastTime(null))); + // 测试 followUpStatus 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setFollowUpStatus(null))); + // 准备参数 + CrmBusinessPageReqVO reqVO = new CrmBusinessPageReqVO(); + reqVO.setName(null); + reqVO.setStatusTypeId(null); + reqVO.setStatusId(null); + reqVO.setContactNextTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + reqVO.setCustomerId(null); + reqVO.setDealTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + reqVO.setPrice(null); + reqVO.setDiscountPercent(null); + reqVO.setProductPrice(null); + reqVO.setRemark(null); + reqVO.setOwnerUserId(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + reqVO.setRoUserIds(null); + reqVO.setRwUserIds(null); + reqVO.setEndStatus(null); + reqVO.setEndRemark(null); + reqVO.setContactLastTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + reqVO.setFollowUpStatus(null); + + // 调用 + PageResult pageResult = businessService.getBusinessPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbBusiness, pageResult.getList().get(0)); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetBusinessList() { + // mock 数据 + CrmBusinessDO dbBusiness = randomPojo(CrmBusinessDO.class, o -> { // 等会查询到 + o.setName(null); + o.setStatusTypeId(null); + o.setStatusId(null); + o.setContactNextTime(null); + o.setCustomerId(null); + o.setDealTime(null); + o.setPrice(null); + o.setDiscountPercent(null); + o.setProductPrice(null); + o.setRemark(null); + o.setOwnerUserId(null); + o.setCreateTime(null); + o.setRoUserIds(null); + o.setRwUserIds(null); + o.setEndStatus(null); + o.setEndRemark(null); + o.setContactLastTime(null); + o.setFollowUpStatus(null); + }); + businessMapper.insert(dbBusiness); + // 测试 name 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setName(null))); + // 测试 statusTypeId 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setStatusTypeId(null))); + // 测试 statusId 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setStatusId(null))); + // 测试 contactNextTime 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setContactNextTime(null))); + // 测试 customerId 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setCustomerId(null))); + // 测试 dealTime 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setDealTime(null))); + // 测试 price 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setPrice(null))); + // 测试 discountPercent 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setDiscountPercent(null))); + // 测试 productPrice 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setProductPrice(null))); + // 测试 remark 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setRemark(null))); + // 测试 ownerUserId 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setOwnerUserId(null))); + // 测试 createTime 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setCreateTime(null))); + // 测试 roUserIds 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setRoUserIds(null))); + // 测试 rwUserIds 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setRwUserIds(null))); + // 测试 endStatus 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setEndStatus(null))); + // 测试 endRemark 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setEndRemark(null))); + // 测试 contactLastTime 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setContactLastTime(null))); + // 测试 followUpStatus 不匹配 + businessMapper.insert(cloneIgnoreId(dbBusiness, o -> o.setFollowUpStatus(null))); + // 准备参数 + CrmBusinessExportReqVO reqVO = new CrmBusinessExportReqVO(); + reqVO.setName(null); + reqVO.setStatusTypeId(null); + reqVO.setStatusId(null); + reqVO.setContactNextTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + reqVO.setCustomerId(null); + reqVO.setDealTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + reqVO.setPrice(null); + reqVO.setDiscountPercent(null); + reqVO.setProductPrice(null); + reqVO.setRemark(null); + reqVO.setOwnerUserId(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + reqVO.setRoUserIds(null); + reqVO.setRwUserIds(null); + reqVO.setEndStatus(null); + reqVO.setEndRemark(null); + reqVO.setContactLastTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + reqVO.setFollowUpStatus(null); + + // 调用 + List list = businessService.getBusinessList(reqVO); + // 断言 + assertEquals(1, list.size()); + assertPojoEquals(dbBusiness, list.get(0)); + } + +} From 01490c879c822f5732c5b9dc55831a002ee10f11 Mon Sep 17 00:00:00 2001 From: ljlleo Date: Fri, 20 Oct 2023 16:14:45 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E5=95=86=E6=9C=BAsql?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/mysql/crm.sql | 31 +++++++++++++++++++++- sql/mysql/crm_menu.sql | 60 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/sql/mysql/crm.sql b/sql/mysql/crm.sql index 6c5594068..24cc3c623 100644 --- a/sql/mysql/crm.sql +++ b/sql/mysql/crm.sql @@ -60,4 +60,33 @@ CREATE TABLE `crm_clue` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '线索表' ROW_FORMAT = Dynamic; \ No newline at end of file +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '线索表' ROW_FORMAT = Dynamic; + +DROP TABLE IF EXISTS `crm_business`; +CREATE TABLE `crm_business` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', + `name` varchar(100) NOT NULL COMMENT '商机名称', + `status_type_id` bigint DEFAULT NULL COMMENT '商机状态类型编号', + `status_id` bigint DEFAULT NULL COMMENT '商机状态编号', + `contact_next_time` datetime DEFAULT NULL COMMENT '下次联系时间', + `customer_id` bigint NOT NULL COMMENT '客户编号', + `deal_time` datetime DEFAULT NULL COMMENT '预计成交日期', + `price` decimal(18,2) DEFAULT NULL COMMENT '商机金额', + `discount_percent` decimal(10,2) DEFAULT NULL COMMENT '整单折扣', + `product_price` decimal(18,2) DEFAULT NULL COMMENT '产品总金额', + `remark` varchar(500) DEFAULT NULL COMMENT '备注', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '创建人', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '更新人', + `owner_user_id` bigint DEFAULT NULL COMMENT '负责人的用户编号', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间', + `ro_user_ids` longtext NOT NULL COMMENT '只读权限的用户编号数组', + `rw_user_ids` longtext NOT NULL COMMENT '读写权限的用户编号数组', + `end_status` int NOT NULL COMMENT '1赢单2输单3无效', + `end_remark` varchar(500) DEFAULT NULL COMMENT '结束时的备注', + `deleted` bit(1) DEFAULT b'0' COMMENT '逻辑删除', + `contact_last_time` datetime DEFAULT NULL COMMENT '最后跟进时间', + `follow_up_status` int DEFAULT NULL COMMENT '跟进状态', + `tenant_id` bigint DEFAULT '0' COMMENT '租户ID', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='商机表'; diff --git a/sql/mysql/crm_menu.sql b/sql/mysql/crm_menu.sql index cf0fe00fd..58c2fd194 100644 --- a/sql/mysql/crm_menu.sql +++ b/sql/mysql/crm_menu.sql @@ -117,3 +117,63 @@ VALUES ( '线索导出', 'crm:clue:export', 3, 5, @parentId, '', '', '', 0 ); + +-- ---------------------------- +-- 合同菜单 +-- ---------------------------- + +-- 菜单 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status, component_name +) +VALUES ( + '商机管理', '', 2, 0, '', + 'business', '', 'crm/business/index', 0, 'CrmBusiness' + ); + +-- 按钮父菜单ID +-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码 +SELECT @parentId := LAST_INSERT_ID(); + +-- 按钮 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '商机查询', 'crm:business:query', 3, 1, @parentId, + '', '', '', 0 + ); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '商机创建', 'crm:business:create', 3, 2, @parentId, + '', '', '', 0 + ); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '商机更新', 'crm:business:update', 3, 3, @parentId, + '', '', '', 0 + ); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '商机删除', 'crm:business:delete', 3, 4, @parentId, + '', '', '', 0 + ); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '商机导出', 'crm:business:export', 3, 5, @parentId, + '', '', '', 0 + );