Commit ef26b5e8dc2512aab50bb25d52c8f92a8ef7ab01

Authored by YunaiV
1 parent c97c9f88

✨ CRM:完善合同的列表实现

Showing 12 changed files with 200 additions and 263 deletions
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessRespVO.java
... ... @@ -130,7 +130,7 @@ public class CrmBusinessRespVO {
130 130 @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00")
131 131 private BigDecimal productPrice;
132 132  
133   - @Schema(description = "合同价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00")
  133 + @Schema(description = "商机价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00")
134 134 private BigDecimal businessPrice;
135 135  
136 136 @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911")
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessSaveReqVO.java
... ... @@ -53,7 +53,7 @@ public class CrmBusinessSaveReqVO {
53 53 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
54 54 private LocalDateTime dealTime;
55 55  
56   - @Schema(description = "整单折扣")
  56 + @Schema(description = "整单折扣", requiredMode = Schema.RequiredMode.REQUIRED, example = "55.00")
57 57 @DiffLogField(name = "整单折扣")
58 58 @NotNull(message = "整单折扣不能为空")
59 59 private BigDecimal discountPercent;
... ... @@ -82,8 +82,8 @@ public class CrmBusinessSaveReqVO {
82 82 @NotNull(message = "产品单价不能为空")
83 83 private BigDecimal productPrice;
84 84  
85   - @Schema(description = "合同价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00")
86   - @NotNull(message = "合同价格不能为空")
  85 + @Schema(description = "商机价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00")
  86 + @NotNull(message = "商机价格不能为空")
87 87 private BigDecimal businessPrice;
88 88  
89 89 @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911")
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java
... ... @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.lang.Assert;
5 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
6 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
7 8 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
8 9 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
9 10 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
... ... @@ -12,18 +13,17 @@ import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageR
12 13 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractRespVO;
13 14 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractSaveReqVO;
14 15 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTransferReqVO;
15   -import cn.iocoder.yudao.module.crm.convert.contract.CrmContractConvert;
16 16 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
17 17 import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO;
18 18 import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
19   -import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractProductDO;
20 19 import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
21   -import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;
22 20 import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService;
23 21 import cn.iocoder.yudao.module.crm.service.contact.CrmContactService;
24 22 import cn.iocoder.yudao.module.crm.service.contract.CrmContractService;
25 23 import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
26 24 import cn.iocoder.yudao.module.crm.service.product.CrmProductService;
  25 +import cn.iocoder.yudao.module.system.api.dept.DeptApi;
  26 +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
27 27 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
28 28 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
29 29 import io.swagger.v3.oas.annotations.Operation;
... ... @@ -44,6 +44,7 @@ import java.util.stream.Stream;
44 44  
45 45 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
46 46 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
  47 +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
47 48 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
48 49 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
49 50 import static java.util.Collections.singletonList;
... ... @@ -64,8 +65,11 @@ public class CrmContractController {
64 65 private CrmBusinessService businessService;
65 66 @Resource
66 67 private CrmProductService productService;
  68 +
67 69 @Resource
68 70 private AdminUserApi adminUserApi;
  71 + @Resource
  72 + private DeptApi deptApi;
69 73  
70 74 @PostMapping("/create")
71 75 @Operation(summary = "创建合同")
... ... @@ -96,15 +100,21 @@ public class CrmContractController {
96 100 @Parameter(name = "id", description = "编号", required = true, example = "1024")
97 101 @PreAuthorize("@ss.hasPermission('crm:contract:query')")
98 102 public CommonResult<CrmContractRespVO> getContract(@RequestParam("id") Long id) {
99   - // 1. 查询合同
100 103 CrmContractDO contract = contractService.getContract(id);
  104 + return success(buildContractDetail(contract));
  105 + }
  106 +
  107 + private CrmContractRespVO buildContractDetail(CrmContractDO contract) {
101 108 if (contract == null) {
102   - return success(null);
  109 + return null;
103 110 }
104   -
105   - // 2. 拼接合同信息
106   - List<CrmContractRespVO> respVOList = buildContractDetailList(singletonList(contract));
107   - return success(respVOList.get(0));
  111 +// List<CrmProductDO> productList = null;
  112 +// if (contractList.size() == 1) {
  113 +// List<CrmContractProductDO> contractProductList = contractService.getContractProductListByContractId(contractList.get(0).getId());
  114 +// contractProductMap = convertMap(contractProductList, CrmContractProductDO::getProductId);
  115 +// productList = productService.getProductList(convertSet(contractProductList, CrmContractProductDO::getProductId));
  116 +// }
  117 + return buildContractDetailList(singletonList(contract)).get(0);
108 118 }
109 119  
110 120 @GetMapping("/page")
... ... @@ -161,27 +171,35 @@ public class CrmContractController {
161 171 if (CollUtil.isEmpty(contractList)) {
162 172 return Collections.emptyList();
163 173 }
164   - // 1. 获取客户列表
165   - List<CrmCustomerDO> customerList = customerService.getCustomerList(
  174 + // 1.1 获取客户列表
  175 + Map<Long, CrmCustomerDO> customerMap = customerService.getCustomerMap(
166 176 convertSet(contractList, CrmContractDO::getCustomerId));
167   - // 2. 获取创建人、负责人列表
  177 + // 1.2 获取创建人、负责人列表
168 178 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(contractList,
169 179 contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId())));
170   - // 3. 获取联系人
  180 + Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
  181 + // 1.3 获取联系人
171 182 Map<Long, CrmContactDO> contactMap = convertMap(contactService.getContactList(convertSet(contractList,
172   - CrmContractDO::getContactId)), CrmContactDO::getId);
173   - // 4. 获取商机
  183 + CrmContractDO::getSignContactId)), CrmContactDO::getId);
  184 + // 1.4 获取商机
174 185 Map<Long, CrmBusinessDO> businessMap = convertMap(businessService.getBusinessList(convertSet(contractList,
175 186 CrmContractDO::getBusinessId)), CrmBusinessDO::getId);
176   - // 5. 获取合同关联的商品
177   - Map<Long, CrmContractProductDO> contractProductMap = null;
178   - List<CrmProductDO> productList = null;
179   - if (contractList.size() == 1) {
180   - List<CrmContractProductDO> contractProductList = contractService.getContractProductListByContractId(contractList.get(0).getId());
181   - contractProductMap = convertMap(contractProductList, CrmContractProductDO::getProductId);
182   - productList = productService.getProductList(convertSet(contractProductList, CrmContractProductDO::getProductId));
183   - }
184   - return CrmContractConvert.INSTANCE.convertList(contractList, userMap, customerList, contactMap, businessMap, contractProductMap, productList);
  187 + // 2. 拼接数据
  188 + return BeanUtils.toBean(contractList, CrmContractRespVO.class, contractVO -> {
  189 + // 2.1 设置客户信息
  190 + findAndThen(customerMap, contractVO.getCustomerId(), customer -> contractVO.setCustomerName(customer.getName()));
  191 + // 2.2 设置用户信息
  192 + findAndThen(userMap, Long.parseLong(contractVO.getCreator()), user -> contractVO.setCreatorName(user.getNickname()));
  193 + MapUtils.findAndThen(userMap, contractVO.getOwnerUserId(), user -> {
  194 + contractVO.setOwnerUserName(user.getNickname());
  195 + MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> contractVO.setOwnerUserDeptName(dept.getName()));
  196 + });
  197 + findAndThen(userMap, contractVO.getSignUserId(), user -> contractVO.setSignUserName(user.getNickname()));
  198 + // 2.3 设置联系人信息
  199 + findAndThen(contactMap, contractVO.getSignContactId(), contact -> contractVO.setSignContactName(contact.getName()));
  200 + // 2.4 设置商机信息
  201 + findAndThen(businessMap, contractVO.getBusinessId(), business -> contractVO.setBusinessName(business.getName()));
  202 + });
185 203 }
186 204  
187 205 @GetMapping("/check-contract-count")
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/CrmContractRespVO.java
... ... @@ -6,13 +6,11 @@ import io.swagger.v3.oas.annotations.media.Schema;
6 6 import lombok.AllArgsConstructor;
7 7 import lombok.Data;
8 8 import lombok.NoArgsConstructor;
9   -import org.springframework.format.annotation.DateTimeFormat;
10 9  
  10 +import java.math.BigDecimal;
11 11 import java.time.LocalDateTime;
12 12 import java.util.List;
13 13  
14   -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
15   -
16 14 @Schema(description = "管理后台 - CRM 合同 Response VO")
17 15 @Data
18 16 @ExcelIgnoreUnannotated
... ... @@ -26,6 +24,10 @@ public class CrmContractRespVO {
26 24 @ExcelProperty("合同名称")
27 25 private String name;
28 26  
  27 + @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20230101")
  28 + @ExcelProperty("合同编号")
  29 + private String no;
  30 +
29 31 @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18336")
30 32 @ExcelProperty("客户编号")
31 33 private Long customerId;
... ... @@ -40,72 +42,70 @@ public class CrmContractRespVO {
40 42 @ExcelProperty("商机名称")
41 43 private String businessName;
42 44  
  45 + @Schema(description = "最后跟进时间")
  46 + @ExcelProperty("最后跟进时间")
  47 + private LocalDateTime contactLastTime;
  48 +
  49 + @Schema(description = "负责人的用户编号", example = "25682")
  50 + @ExcelProperty("负责人的用户编号")
  51 + private Long ownerUserId;
  52 + @Schema(description = "负责人名字", example = "25682")
  53 + @ExcelProperty("负责人名字")
  54 + private String ownerUserName;
  55 + @Schema(description = "负责人部门")
  56 + @ExcelProperty("负责人部门")
  57 + private String ownerUserDeptName;
  58 +
43 59 @Schema(description = "工作流编号", example = "1043")
44 60 @ExcelProperty("工作流编号")
45 61 private Long processInstanceId;
46 62  
  63 + @Schema(description = "审批状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
  64 + @ExcelProperty("审批状态")
  65 + private Integer auditStatus;
  66 +
47 67 @Schema(description = "下单日期", requiredMode = Schema.RequiredMode.REQUIRED)
48 68 @ExcelProperty("下单日期")
49   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
50 69 private LocalDateTime orderDate;
51 70  
52   - @Schema(description = "负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17144")
53   - @ExcelProperty("负责人的用户编号")
54   - private Long ownerUserId;
55   -
56   - // TODO @芋艿:未来应该支持自动生成;
57   - @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20230101")
58   - @ExcelProperty("合同编号")
59   - private String no;
60   -
61 71 @Schema(description = "开始时间")
62 72 @ExcelProperty("开始时间")
63   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
64 73 private LocalDateTime startTime;
65 74  
66 75 @Schema(description = "结束时间")
67 76 @ExcelProperty("结束时间")
68   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
69 77 private LocalDateTime endTime;
70 78  
71   - @Schema(description = "合同金额", example = "5617")
72   - @ExcelProperty("合同金额")
73   - private Integer price;
  79 + @Schema(description = "产品总金额", example = "19510")
  80 + @ExcelProperty("产品总金额")
  81 + private BigDecimal totalProductPrice;
74 82  
75 83 @Schema(description = "整单折扣")
76 84 @ExcelProperty("整单折扣")
77   - private Integer discountPercent;
  85 + private BigDecimal discountPercent;
78 86  
79   - @Schema(description = "产品总金额", example = "19510")
80   - @ExcelProperty("产品总金额")
81   - private Integer productPrice;
  87 + @Schema(description = "合同金额", example = "5617")
  88 + @ExcelProperty("合同金额")
  89 + private BigDecimal totalPrice;
82 90  
83   - @Schema(description = "联系人编号", example = "18546")
84   - @ExcelProperty("联系人编号")
85   - private Long contactId;
86   - @Schema(description = "联系人编号", example = "18546")
87   - @ExcelProperty("联系人编号")
88   - private String contactName;
  91 + @Schema(description = "客户签约人编号", example = "18546")
  92 + private Long signContactId;
  93 + @Schema(description = "客户签约人", example = "小豆")
  94 + @ExcelProperty("客户签约人")
  95 + private String signContactName;
89 96  
90 97 @Schema(description = "公司签约人", example = "14036")
91   - @ExcelProperty("公司签约人")
92 98 private Long signUserId;
93   - @Schema(description = "公司签约人", example = "14036")
  99 + @Schema(description = "公司签约人", example = "小明")
94 100 @ExcelProperty("公司签约人")
95 101 private String signUserName;
96 102  
97   - @Schema(description = "最后跟进时间")
98   - @ExcelProperty("最后跟进时间")
99   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
100   - private LocalDateTime contactLastTime;
101   -
102 103 @Schema(description = "备注", example = "你猜")
103 104 @ExcelProperty("备注")
104 105 private String remark;
105 106  
106 107 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
107 108 @ExcelProperty("创建时间")
108   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
109 109 private LocalDateTime createTime;
110 110  
111 111 @Schema(description = "创建人", example = "25682")
... ... @@ -118,19 +118,10 @@ public class CrmContractRespVO {
118 118  
119 119 @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
120 120 @ExcelProperty("更新时间")
121   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
122 121 private LocalDateTime updateTime;
123 122  
124   - @Schema(description = "负责人", example = "test")
125   - @ExcelProperty("负责人")
126   - private String ownerUserName;
127   -
128   - @Schema(description = "审批状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
129   - @ExcelProperty("审批状态")
130   - private Integer auditStatus;
131   -
132 123 @Schema(description = "产品列表")
133   - private List<Item> items;
  124 + private List<Item> products;
134 125  
135 126 @Schema(description = "产品列表")
136 127 @Data
... ... @@ -138,26 +129,29 @@ public class CrmContractRespVO {
138 129 @AllArgsConstructor
139 130 public static class Item {
140 131  
141   - @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529")
  132 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888")
142 133 private Long id;
143 134  
144   - @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是产品")
145   - private String name;
146   -
147   - @Schema(description = "产品编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "N881")
148   - private String no;
  135 + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529")
  136 + private Long productId;
  137 + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
  138 + private String productName;
  139 + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529")
  140 + private String productNo;
  141 + @Schema(description = "产品单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
  142 + private Integer productUnit;
149 143  
150   - @Schema(description = "单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
151   - private Integer unit;
  144 + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00")
  145 + private BigDecimal productPrice;
152 146  
153   - @Schema(description = "价格,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
154   - private Integer price;
  147 + @Schema(description = "合同价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00")
  148 + private BigDecimal businessPrice;
155 149  
156   - @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
157   - private Integer count;
  150 + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911")
  151 + private BigDecimal count;
158 152  
159   - @Schema(description = "产品折扣", example = "99")
160   - private Integer discountPercent;
  153 + @Schema(description = "总计价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00")
  154 + private BigDecimal totalPrice;
161 155  
162 156 }
163 157  
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/CrmContractSaveReqVO.java
... ... @@ -12,6 +12,7 @@ import lombok.Data;
12 12 import lombok.NoArgsConstructor;
13 13 import org.springframework.format.annotation.DateTimeFormat;
14 14  
  15 +import java.math.BigDecimal;
15 16 import java.time.LocalDateTime;
16 17 import java.util.List;
17 18  
... ... @@ -38,22 +39,16 @@ public class CrmContractSaveReqVO {
38 39 @DiffLogField(name = "商机", function = CrmBusinessParseFunction.NAME)
39 40 private Long businessId;
40 41  
41   - @Schema(description = "下单日期", requiredMode = Schema.RequiredMode.REQUIRED)
42   - @DiffLogField(name = "下单日期")
43   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
44   - @NotNull(message = "下单日期不能为空")
45   - private LocalDateTime orderDate;
46   -
47 42 @Schema(description = "负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17144")
48 43 @DiffLogField(name = "负责人", function = SysAdminUserParseFunction.NAME)
49 44 @NotNull(message = "负责人不能为空")
50 45 private Long ownerUserId;
51 46  
52   - // TODO @芋艿:未来应该支持自动生成;
53   - @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20230101")
54   - @DiffLogField(name = "合同编号")
55   - @NotNull(message = "合同编号不能为空")
56   - private String no;
  47 + @Schema(description = "下单日期", requiredMode = Schema.RequiredMode.REQUIRED)
  48 + @DiffLogField(name = "下单日期")
  49 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  50 + @NotNull(message = "下单日期不能为空")
  51 + private LocalDateTime orderDate;
57 52  
58 53 @Schema(description = "开始时间")
59 54 @DiffLogField(name = "开始时间")
... ... @@ -65,21 +60,18 @@ public class CrmContractSaveReqVO {
65 60 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
66 61 private LocalDateTime endTime;
67 62  
68   - @Schema(description = "合同金额", example = "5617")
69   - @DiffLogField(name = "合同金额")
70   - private Integer price;
71   -
72   - @Schema(description = "整单折扣")
  63 + @Schema(description = "整单折扣", requiredMode = Schema.RequiredMode.REQUIRED, example = "55.00")
73 64 @DiffLogField(name = "整单折扣")
74   - private Integer discountPercent;
  65 + @NotNull(message = "整单折扣不能为空")
  66 + private BigDecimal discountPercent;
75 67  
76   - @Schema(description = "产品总金额", example = "19510")
77   - @DiffLogField(name = "产品总金额")
78   - private Integer productPrice;
  68 + @Schema(description = "合同金额", example = "5617")
  69 + @DiffLogField(name = "合同金额")
  70 + private BigDecimal totalPrice;
79 71  
80   - @Schema(description = "联系人编号", example = "18546")
81   - @DiffLogField(name = "联系人", function = CrmContactParseFunction.NAME)
82   - private Long contactId;
  72 + @Schema(description = "客户签约人编号", example = "18546")
  73 + @DiffLogField(name = "客户签约人", function = CrmContactParseFunction.NAME)
  74 + private Long signContactId;
83 75  
84 76 @Schema(description = "公司签约人", example = "14036")
85 77 @DiffLogField(name = "公司签约人", function = SysAdminUserParseFunction.NAME)
... ... @@ -89,27 +81,31 @@ public class CrmContractSaveReqVO {
89 81 @DiffLogField(name = "备注")
90 82 private String remark;
91 83  
92   -
93 84 @Schema(description = "产品列表")
94   - private List<CrmContractProductItem> productItems;
  85 + private List<Product> products;
95 86  
96 87 @Schema(description = "产品列表")
97 88 @Data
98 89 @NoArgsConstructor
99 90 @AllArgsConstructor
100   - public static class CrmContractProductItem {
  91 + public static class Product {
101 92  
102   - @Schema(description = "产品编号", example = "20529")
  93 + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529")
103 94 @NotNull(message = "产品编号不能为空")
104   - private Long id;
  95 + private Long productId;
  96 +
  97 + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00")
  98 + @NotNull(message = "产品单价不能为空")
  99 + private BigDecimal productPrice;
  100 +
  101 + @Schema(description = "合同价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00")
  102 + @NotNull(message = "合同价格不能为空")
  103 + private BigDecimal businessPrice;
105 104  
106 105 @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911")
107 106 @NotNull(message = "产品数量不能为空")
108 107 private Integer count;
109 108  
110   - @Schema(description = "产品折扣")
111   - private Integer discountPercent;
112   -
113 109 }
114 110  
115 111 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/contract/CrmContractConvert.java deleted
1   -package cn.iocoder.yudao.module.crm.convert.contract;
2   -
3   -import cn.hutool.core.collection.CollUtil;
4   -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
5   -import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
6   -import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractRespVO;
7   -import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTransferReqVO;
8   -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
9   -import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO;
10   -import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
11   -import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractProductDO;
12   -import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
13   -import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;
14   -import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO;
15   -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
16   -import org.mapstruct.Mapper;
17   -import org.mapstruct.Mapping;
18   -import org.mapstruct.factory.Mappers;
19   -
20   -import java.util.List;
21   -import java.util.Map;
22   -
23   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
24   -import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
25   -
26   -/**
27   - * 合同 Convert
28   - *
29   - * @author dhb52
30   - */
31   -@Mapper
32   -public interface CrmContractConvert {
33   -
34   - CrmContractConvert INSTANCE = Mappers.getMapper(CrmContractConvert.class);
35   -
36   - @Mapping(target = "bizId", source = "reqVO.id")
37   - CrmPermissionTransferReqBO convert(CrmContractTransferReqVO reqVO, Long userId);
38   -
39   - default List<CrmContractRespVO> convertList(List<CrmContractDO> contractList, Map<Long, AdminUserRespDTO> userMap,
40   - List<CrmCustomerDO> customerList, Map<Long, CrmContactDO> contactMap,
41   - Map<Long, CrmBusinessDO> businessMap, Map<Long, CrmContractProductDO> contractProductMap,
42   - List<CrmProductDO> productList) {
43   - List<CrmContractRespVO> respVOList = BeanUtils.toBean(contractList, CrmContractRespVO.class);
44   - // 拼接关联字段
45   - Map<Long, CrmCustomerDO> customerMap = convertMap(customerList, CrmCustomerDO::getId);
46   - respVOList.forEach(contract -> {
47   - findAndThen(userMap, contract.getOwnerUserId(), user -> contract.setOwnerUserName(user.getNickname()));
48   - findAndThen(userMap, Long.parseLong(contract.getCreator()), user -> contract.setCreatorName(user.getNickname()));
49   - findAndThen(userMap, contract.getSignUserId(), user -> contract.setSignUserName(user.getNickname()));
50   - findAndThen(customerMap, contract.getCustomerId(), customer -> contract.setCustomerName(customer.getName()));
51   - findAndThen(contactMap, contract.getContactId(), contact -> contract.setContactName(contact.getName()));
52   - findAndThen(businessMap, contract.getBusinessId(), business -> contract.setBusinessName(business.getName()));
53   - });
54   - if (CollUtil.isNotEmpty(respVOList) && respVOList.size() == 1) {
55   - setContractRespVOProductItems(respVOList.get(0), contractProductMap, productList);
56   - }
57   - return respVOList;
58   - }
59   -
60   - default void setContractRespVOProductItems(CrmContractRespVO respVO, Map<Long, CrmContractProductDO> contractProductMap,
61   - List<CrmProductDO> productList) {
62   - respVO.setItems(CollectionUtils.convertList(productList, product -> {
63   - CrmContractRespVO.Item productItemRespVO = BeanUtils.toBean(product, CrmContractRespVO.Item.class);
64   - findAndThen(contractProductMap, product.getId(), contractProduct ->
65   - productItemRespVO.setCount(contractProduct.getCount()).setDiscountPercent(contractProduct.getDiscountPercent()));
66   - return productItemRespVO;
67   - }));
68   - }
69   -
70   -}
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessProductDO.java
... ... @@ -50,7 +50,7 @@ public class CrmBusinessProductDO extends BaseDO {
50 50 */
51 51 private BigDecimal productPrice;
52 52 /**
53   - * 合同价格, 单位:元
  53 + * 商机价格, 单位:元
54 54 */
55 55 private BigDecimal businessPrice;
56 56 /**
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractDO.java
... ... @@ -10,9 +10,9 @@ import com.baomidou.mybatisplus.annotation.TableId;
10 10 import com.baomidou.mybatisplus.annotation.TableName;
11 11 import lombok.*;
12 12  
  13 +import java.math.BigDecimal;
13 14 import java.time.LocalDateTime;
14 15  
15   -// TODO 芋艿:实体的梳理
16 16 /**
17 17 * CRM 合同 DO
18 18 *
... ... @@ -34,25 +34,38 @@ public class CrmContractDO extends BaseDO {
34 34 @TableId
35 35 private Long id;
36 36 /**
37   - * 合同编号
38   - */
39   - private String no;
40   - /**
41 37 * 合同名称
42 38 */
43 39 private String name;
44 40 /**
  41 + * 合同编号
  42 + */
  43 + private String no;
  44 + /**
45 45 * 客户编号
46 46 *
47 47 * 关联 {@link CrmCustomerDO#getId()}
48 48 */
49 49 private Long customerId;
50 50 /**
51   - * 商机编号
  51 + * 商机编号,非必须
52 52 *
53 53 * 关联 {@link CrmBusinessDO#getId()}
54 54 */
55 55 private Long businessId;
  56 +
  57 + /**
  58 + * 最后跟进时间
  59 + */
  60 + private LocalDateTime contactLastTime;
  61 +
  62 + /**
  63 + * 负责人的用户编号
  64 + *
  65 + * 关联 AdminUserDO 的 id 字段
  66 + */
  67 + private Long ownerUserId;
  68 +
56 69 /**
57 70 * 工作流编号
58 71 *
... ... @@ -60,6 +73,13 @@ public class CrmContractDO extends BaseDO {
60 73 */
61 74 private String processInstanceId;
62 75 /**
  76 + * 审批状态
  77 + *
  78 + * 枚举 {@link CrmAuditStatusEnum}
  79 + */
  80 + private Integer auditStatus;
  81 +
  82 + /**
63 83 * 下单日期
64 84 */
65 85 private LocalDateTime orderDate;
... ... @@ -72,50 +92,32 @@ public class CrmContractDO extends BaseDO {
72 92 */
73 93 private LocalDateTime endTime;
74 94 /**
75   - * 合同金额,单位:分
  95 + * 产品总金额,单位:元
76 96 */
77   - private Integer price;
  97 + private BigDecimal totalProductPrice;
78 98 /**
79 99 * 整单折扣
80 100 */
81   - private Integer discountPercent;
  101 + private BigDecimal discountPercent;
82 102 /**
83   - * 产品总金额,单位:分
  103 + * 合同总金额,单位:分
84 104 */
85   - private Integer productPrice;
  105 + private BigDecimal totalPrice;
86 106 /**
87   - * 客户签约人
  107 + * 客户签约人,非必须
88 108 *
89 109 * 关联 {@link CrmContactDO#getId()}
90 110 */
91   - private Long contactId;
  111 + private Long signContactId;
92 112 /**
93   - * 公司签约人
  113 + * 公司签约人,非必须
94 114 *
95 115 * 关联 AdminUserDO 的 id 字段
96 116 */
97 117 private Long signUserId;
98 118 /**
99   - * 最后跟进时间
100   - */
101   - private LocalDateTime contactLastTime;
102   - /**
103 119 * 备注
104 120 */
105 121 private String remark;
106 122  
107   - /**
108   - * 负责人的用户编号
109   - *
110   - * 关联 AdminUserDO 的 id 字段
111   - */
112   - private Long ownerUserId;
113   -
114   - /**
115   - * 审批状态
116   - *
117   - * 枚举 {@link CrmAuditStatusEnum}
118   - */
119   - private Integer auditStatus;
120   -
121 123 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractProductDO.java
... ... @@ -7,8 +7,10 @@ import com.baomidou.mybatisplus.annotation.TableId;
7 7 import com.baomidou.mybatisplus.annotation.TableName;
8 8 import lombok.*;
9 9  
  10 +import java.math.BigDecimal;
  11 +
10 12 /**
11   - * 合同产品关联表 DO
  13 + * CRM 合同产品关联表 DO
12 14 *
13 15 * @author HUIHUI
14 16 */
... ... @@ -28,38 +30,33 @@ public class CrmContractProductDO extends BaseDO {
28 30 @TableId
29 31 private Long id;
30 32 /**
31   - * 产品编号
32   - *
33   - * 关联 {@link CrmProductDO#getId()}
34   - */
35   - private Long productId;
36   - /**
37 33 * 合同编号
38 34 *
39 35 * 关联 {@link CrmContractDO#getId()}
40 36 */
41 37 private Long contractId;
42 38 /**
43   - * 产品单价
  39 + * 产品编号
  40 + *
  41 + * 关联 {@link CrmProductDO#getId()}
44 42 */
45   - private Integer price;
  43 + private Long productId;
46 44 /**
47   - * 销售价格, 单位:分
  45 + * 产品单价,单位:元
48 46 */
49   - private Integer salesPrice;
  47 + private Integer productPrice;
50 48 /**
51   - * 数量
  49 + * 合同价格, 单位:分
52 50 */
53   - private Integer count;
  51 + private BigDecimal contractPrice;
54 52 /**
55   - * 折扣
  53 + * 数量
56 54 */
57   - private Integer discountPercent;
  55 + private BigDecimal count;
58 56 /**
59   - * 总计价格(折扣后价格)
60   - * = {@link #price}
61   - * * {@link #count}
62   - * * ({@link #discountPercent / 100})
  57 + * 总计价格,单位:元
  58 + *
  59 + * totalPrice = businessPrice * count
63 60 */
64 61 private Integer totalPrice;
65 62  
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java
... ... @@ -81,7 +81,7 @@ public interface CrmContractMapper extends BaseMapperX&lt;CrmContractDO&gt; {
81 81 }
82 82  
83 83 default Long selectCountByContactId(Long contactId) {
84   - return selectCount(CrmContractDO::getContactId, contactId);
  84 + return selectCount(CrmContractDO::getSignContactId, contactId);
85 85 }
86 86  
87 87 default Long selectCountByBusinessId(Long businessId) {
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java
... ... @@ -141,7 +141,6 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
141 141 // 2.2 更新商机关联商品
142 142 updateBusinessProduct(updateObj.getId(), businessProducts);
143 143  
144   - // TODO @商机待定:如果状态发生变化,插入商机状态变更记录表
145 144 // 3. 记录操作日志上下文
146 145 LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldBusiness, CrmBusinessSaveReqVO.class));
147 146 LogRecordContext.putVariable("businessName", oldBusiness.getName());
... ... @@ -264,7 +263,7 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
264 263 // 1.2 校验是否关联合同
265 264 validateContractExists(id);
266 265  
267   - // 删除
  266 + // 删除商机
268 267 businessMapper.deleteById(id);
269 268 // 删除数据权限
270 269 permissionService.deletePermission(CrmBizTypeEnum.CRM_BUSINESS.getType(), id);
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java
... ... @@ -5,7 +5,6 @@ import cn.hutool.core.collection.ListUtil;
5 5 import cn.hutool.core.lang.Assert;
6 6 import cn.hutool.core.util.ObjUtil;
7 7 import cn.iocoder.yudao.framework.common.pojo.PageResult;
8   -import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
9 8 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
10 9 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
11 10 import cn.iocoder.yudao.module.bpm.api.listener.dto.BpmResultListenerRespDTO;
... ... @@ -15,7 +14,6 @@ import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
15 14 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageReqVO;
16 15 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractSaveReqVO;
17 16 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTransferReqVO;
18   -import cn.iocoder.yudao.module.crm.convert.contract.CrmContractConvert;
19 17 import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
20 18 import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractProductDO;
21 19 import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;
... ... @@ -31,6 +29,7 @@ import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
31 29 import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO;
32 30 import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
33 31 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO;
  32 +import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO;
34 33 import cn.iocoder.yudao.module.crm.service.product.CrmProductService;
35 34 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
36 35 import com.mzt.logapi.context.LogRecordContext;
... ... @@ -95,16 +94,16 @@ public class CrmContractServiceImpl implements CrmContractService {
95 94 CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class).setId(null);
96 95 contractMapper.insert(contract);
97 96 // 1.2 插入合同关联商品
98   - if (CollUtil.isNotEmpty(createReqVO.getProductItems())) { // 如果有的话
  97 + if (CollUtil.isNotEmpty(createReqVO.getProducts())) { // 如果有的话
99 98 List<CrmContractProductDO> productList = convertContractProductList(createReqVO, contract.getId());
100 99 contractProductMapper.insertBatch(productList);
101   - // 更新合同商品总金额
102   - contractMapper.updateById(new CrmContractDO().setId(contract.getId()).setProductPrice(
103   - getSumValue(productList, CrmContractProductDO::getTotalPrice, Integer::sum)));
  100 + // 更新合同商品总金额 TODO 芋艿
  101 +// contractMapper.updateById(new CrmContractDO().setId(contract.getId()).setTotalProductPrice(
  102 +// getSumValue(productList, CrmContractProductDO::getTotalPrice, Integer::sum)));
104 103 // 如果存在合同关联了商机则更新商机商品关联
105 104 if (contract.getBusinessId() != null) {
106 105 businessService.updateBusinessProduct(new CrmBusinessUpdateProductReqBO().setId(contract.getBusinessId())
107   - .setItems(BeanUtils.toBean(createReqVO.getProductItems(), CrmBusinessUpdateProductReqBO.Item.class)));
  106 + .setItems(BeanUtils.toBean(createReqVO.getProducts(), CrmBusinessUpdateProductReqBO.Item.class)));
108 107 }
109 108 }
110 109  
... ... @@ -146,7 +145,7 @@ public class CrmContractServiceImpl implements CrmContractService {
146 145 }
147 146  
148 147 private void updateContractProduct(CrmContractSaveReqVO updateReqVO, Long contractId) {
149   - if (CollUtil.isEmpty(updateReqVO.getProductItems())) {
  148 + if (CollUtil.isEmpty(updateReqVO.getProducts())) {
150 149 return;
151 150 }
152 151 List<CrmContractProductDO> newProductList = convertContractProductList(updateReqVO, contractId);
... ... @@ -173,20 +172,22 @@ public class CrmContractServiceImpl implements CrmContractService {
173 172  
174 173 private List<CrmContractProductDO> convertContractProductList(CrmContractSaveReqVO reqVO, Long contractId) {
175 174 // 校验商品存在
176   - Set<Long> productIds = convertSet(reqVO.getProductItems(), CrmContractSaveReqVO.CrmContractProductItem::getId);
  175 + Set<Long> productIds = convertSet(reqVO.getProducts(), CrmContractSaveReqVO.Product::getProductId);
177 176 List<CrmProductDO> productList = productService.getProductList(productIds);
178 177 if (CollUtil.isEmpty(productIds) || productList.size() != productIds.size()) {
179 178 throw exception(PRODUCT_NOT_EXISTS);
180 179 }
181 180 Map<Long, CrmProductDO> productMap = convertMap(productList, CrmProductDO::getId);
182   - return convertList(reqVO.getProductItems(), productItem -> {
183   - CrmProductDO product = productMap.get(productItem.getId());
184   - return BeanUtils.toBean(product, CrmContractProductDO.class)
185   - .setId(null).setProductId(productItem.getId()).setContractId(contractId)
186   - .setCount(productItem.getCount()).setDiscountPercent(productItem.getDiscountPercent())
187   - // TODO 芋艿:这里临时注释掉
188   - .setTotalPrice(MoneyUtils.calculator(null, productItem.getCount(), productItem.getDiscountPercent()));
189   - });
  181 + // TODO 芋艿
  182 + return null;
  183 +// return convertList(reqVO.getProducts(), productItem -> {
  184 +// CrmProductDO product = productMap.get(productItem.getId());
  185 +// return BeanUtils.toBean(product, CrmContractProductDO.class)
  186 +// .setId(null).setProductId(productItem.getId()).setContractId(contractId)
  187 +// .setCount(productItem.getCount()).setDiscountPercent(productItem.getDiscountPercent())
  188 +// // TODO 芋艿:这里临时注释掉
  189 +// .setTotalPrice(MoneyUtils.calculator(null, productItem.getCount(), productItem.getDiscountPercent()));
  190 +// });
190 191 }
191 192  
192 193 /**
... ... @@ -245,8 +246,8 @@ public class CrmContractServiceImpl implements CrmContractService {
245 246 CrmContractDO contract = validateContractExists(reqVO.getId());
246 247  
247 248 // 2.1 数据权限转移
248   - crmPermissionService.transferPermission(
249   - CrmContractConvert.INSTANCE.convert(reqVO, userId).setBizType(CrmBizTypeEnum.CRM_CONTRACT.getType()));
  249 + crmPermissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_CONTRACT.getType(),
  250 + reqVO.getId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel()));
250 251 // 2.2 设置负责人
251 252 contractMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId());
252 253  
... ...