Commit 52a68e18388a4c6f5395d500b1a149eb26e2de6a

Authored by YunaiV
1 parent 278f220c

📖 CRM:code review 合同金额排行榜、回款金额排行榜

Showing 13 changed files with 92 additions and 22 deletions
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/BiRankingController.http
@@ -3,8 +3,7 @@ GET {{baseUrl}}/bi/rank/contract-ranKing @@ -3,8 +3,7 @@ GET {{baseUrl}}/bi/rank/contract-ranKing
3 Authorization: Bearer {{token}} 3 Authorization: Bearer {{token}}
4 tenant-id: {{adminTenentId}} 4 tenant-id: {{adminTenentId}}
5 5
6 -  
7 ### 回款金额排行榜 6 ### 回款金额排行榜
8 GET {{baseUrl}}/bi/rank/receivables-ranKing 7 GET {{baseUrl}}/bi/rank/receivables-ranKing
9 Authorization: Bearer {{token}} 8 Authorization: Bearer {{token}}
10 -tenant-id: {{adminTenentId}} 9 -tenant-id: {{adminTenentId}}
  10 +tenant-id: {{adminTenentId}}
11 \ No newline at end of file 11 \ No newline at end of file
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/BiRankingController.java
@@ -19,6 +19,7 @@ import java.util.List; @@ -19,6 +19,7 @@ import java.util.List;
19 19
20 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 20 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
21 21
  22 +// TODO @anhaohao:写了 swagger 注解,不写注释哈
22 /** 23 /**
23 * @author anhaohao 24 * @author anhaohao
24 */ 25 */
@@ -50,4 +51,5 @@ public class BiRankingController { @@ -50,4 +51,5 @@ public class BiRankingController {
50 public CommonResult<List<BiReceivablesRanKingRespVO>> receivablesRanKing(BiRankReqVO biRankReqVO) { 51 public CommonResult<List<BiReceivablesRanKingRespVO>> receivablesRanKing(BiRankReqVO biRankReqVO) {
51 return success(biRankingService.receivablesRanKing(biRankReqVO)); 52 return success(biRankingService.receivablesRanKing(biRankReqVO));
52 } 53 }
  54 +
53 } 55 }
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiContractRanKingRespVO.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bi.controller.admin.ranking.vo; @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bi.controller.admin.ranking.vo;
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 import lombok.Data; 4 import lombok.Data;
5 5
  6 +// TODO @anhaohao:VO 类有 swagger 注解,不写注释哈
6 /** 7 /**
7 * 管理后台 - BI 排行榜 Response VO 8 * 管理后台 - BI 排行榜 Response VO
8 * 9 *
@@ -12,13 +13,14 @@ import lombok.Data; @@ -12,13 +13,14 @@ import lombok.Data;
12 @Data 13 @Data
13 public class BiContractRanKingRespVO { 14 public class BiContractRanKingRespVO {
14 15
  16 + // TODO @anhaohao:如果一定返回的字段,需要加 requiredMode = Schema.RequiredMode.REQUIRED, 哈
15 @Schema(description = "金额", example = "1") 17 @Schema(description = "金额", example = "1")
16 private Integer price; 18 private Integer price;
17 19
18 @Schema(description = "姓名", example = "1") 20 @Schema(description = "姓名", example = "1")
19 private String nickname; 21 private String nickname;
20 22
21 -  
22 @Schema(description = "部门名称", example = "1") 23 @Schema(description = "部门名称", example = "1")
23 private String deptName; 24 private String deptName;
  25 +
24 } 26 }
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiParams.java
@@ -7,6 +7,7 @@ import lombok.EqualsAndHashCode; @@ -7,6 +7,7 @@ import lombok.EqualsAndHashCode;
7 7
8 import java.util.List; 8 import java.util.List;
9 9
  10 +// TODO @anhaohao:这个类的命名,还是保持和其它一致使用 ReqVO 结尾;例如说,CrmStatisticsCommonParamReqVO
10 /** 11 /**
11 * @author anhaohao 12 * @author anhaohao
12 * bi参数 13 * bi参数
@@ -25,17 +26,19 @@ public class BiParams extends PageParam { @@ -25,17 +26,19 @@ public class BiParams extends PageParam {
25 @Schema(description = "用户IDs") 26 @Schema(description = "用户IDs")
26 private List<Long> userIds; 27 private List<Long> userIds;
27 28
  29 + // TODO @anhaohao:这个字段,可以融合到 startTime、endTime 里去,交给前端计算哈;
28 @Schema(description = "类型") 30 @Schema(description = "类型")
29 private String type; 31 private String type;
30 32
  33 + // TODO @anhaohao:还是使用 LocalDateTime
31 @Schema(description = "开始时间") 34 @Schema(description = "开始时间")
32 private String startTime; 35 private String startTime;
33 36
34 @Schema(description = "结束时间") 37 @Schema(description = "结束时间")
35 private String endTime; 38 private String endTime;
36 39
  40 + // TODO @anhaohao:这个字段,是不是直接只基于 deptId 和 userId 来判断即可哈?
37 @Schema(description = "0 部门 1员工") 41 @Schema(description = "0 部门 1员工")
38 private Integer isUser = 1; 42 private Integer isUser = 1;
39 43
40 -  
41 } 44 }
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiRankReqVO.java
@@ -15,6 +15,8 @@ public class BiRankReqVO { @@ -15,6 +15,8 @@ public class BiRankReqVO {
15 @Schema(description = "部门id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 15 @Schema(description = "部门id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
16 private Long deptId; 16 private Long deptId;
17 17
  18 + // TODO @anhaohao:这个字段,参考 BiParams 的 type 建议
18 @Schema(description = "分析类型(1.今天 2.昨天 3.本周 4.上周 5.本月 6.上月 7.本季度 8.上季度 9.本年 10 上年)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 19 @Schema(description = "分析类型(1.今天 2.昨天 3.本周 4.上周 5.本月 6.上月 7.本季度 8.上季度 9.本年 10 上年)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
19 private String type; 20 private String type;
  21 +
20 } 22 }
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiReceivablesRanKingRespVO.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bi.controller.admin.ranking.vo; @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bi.controller.admin.ranking.vo;
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 import lombok.Data; 4 import lombok.Data;
5 5
  6 +// TODO @anhaohao:参考 BiContractRanKingRespVO 的建议
6 /** 7 /**
7 * 管理后台 - BI 排行榜 Response VO 8 * 管理后台 - BI 排行榜 Response VO
8 * 9 *
@@ -20,4 +21,5 @@ public class BiReceivablesRanKingRespVO { @@ -20,4 +21,5 @@ public class BiReceivablesRanKingRespVO {
20 21
21 @Schema(description = "部门名称", example = "研发部") 22 @Schema(description = "部门名称", example = "研发部")
22 private String deptName; 23 private String deptName;
  24 +
23 } 25 }
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/package-info.java
@@ -3,5 +3,8 @@ @@ -3,5 +3,8 @@
3 * 例如说:报表、图表、数据分析等等 3 * 例如说:报表、图表、数据分析等等
4 * <p> 4 * <p>
5 * 1. Controller URL:以 /bi/ 开头,避免和其它 Module 冲突 5 * 1. Controller URL:以 /bi/ 开头,避免和其它 Module 冲突
  6 + *
  7 + * TODO @anhaohao:mall 当时独立拆分一个 statistics 模块的原因,是因为 mall 拆分了多个模块,没有模块适合承接统计的能力,所以独立了。
  8 + * TODO crm 因为没有拆分,所以可以直接放在 crm 模块下面;这样,我们可以在 controller/admin 和 service 下,新建一个 bi 包,专门放置统计的代码。
6 */ 9 */
7 package cn.iocoder.yudao.module.bi; 10 package cn.iocoder.yudao.module.bi;
8 \ No newline at end of file 11 \ No newline at end of file
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/service/ranking/BiRankingService.java
@@ -11,7 +11,7 @@ import java.util.List; @@ -11,7 +11,7 @@ import java.util.List;
11 * 11 *
12 * @author anhaohao 12 * @author anhaohao
13 */ 13 */
14 -public interface BiRankingService { 14 +public interface BiRankingService { // TODO @anhaohao:第一个方法,和类要有一个空行
15 /** 15 /**
16 * 合同金额排行榜 16 * 合同金额排行榜
17 * 17 *
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/util/BiTimeUtil.java
@@ -28,6 +28,7 @@ public class BiTimeUtil { @@ -28,6 +28,7 @@ public class BiTimeUtil {
28 // 解析时间 28 // 解析时间
29 BiTimeEntity biTimeEntity = analyzeTime(biParams); 29 BiTimeEntity biTimeEntity = analyzeTime(biParams);
30 // 解析权限 30 // 解析权限
  31 + // TODO @anhaohao:涉及到数据的读取,不放在 Util 里,还是搞会到 Service 哈;
31 biTimeEntity.setUserIds(analyzeAuth(biParams)); 32 biTimeEntity.setUserIds(analyzeAuth(biParams));
32 return biTimeEntity; 33 return biTimeEntity;
33 } 34 }
yudao-module-crm/yudao-module-bi-biz/src/main/resources/mapper/rank/BiRankingMapper.xml
@@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
7 resultType="cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiContractRanKingRespVO"> 7 resultType="cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiContractRanKingRespVO">
8 SELECT IFNULL(SUM(t.price), 0) AS price, su.nickname, t.owner_user_id, dept.name AS deptName 8 SELECT IFNULL(SUM(t.price), 0) AS price, su.nickname, t.owner_user_id, dept.name AS deptName
9 FROM crm_contract t 9 FROM crm_contract t
  10 + <!-- TODO @anhaohao:system_users、system_dept 是不是没用到?尽量不连这 2 个表,微服务下会是独立仓库;如果显示需要,可以在 service 读取后拼接; -->
10 LEFT JOIN system_users AS su ON su.id = t.owner_user_id 11 LEFT JOIN system_users AS su ON su.id = t.owner_user_id
11 LEFT JOIN system_dept AS dept ON dept.id = su.dept_id 12 LEFT JOIN system_dept AS dept ON dept.id = su.dept_id
12 WHERE t.deleted = 0 13 WHERE t.deleted = 0
@@ -17,10 +18,12 @@ @@ -17,10 +18,12 @@
17 #{item} 18 #{item}
18 </foreach> 19 </foreach>
19 </if> 20 </if>
  21 + <!-- TODO @anhaohao:在某个区间的时间,这么做有点浪费性能;一般做法是 beginTime 是开始时间(00:00:00),finalTime 是结束时间(23:59:59),这样实现的; -->
20 AND DATE_FORMAT(t.order_date,'${sqlDateFormat}') between #{beginTime} and #{finalTime} 22 AND DATE_FORMAT(t.order_date,'${sqlDateFormat}') between #{beginTime} and #{finalTime}
21 GROUP BY t.owner_user_id 23 GROUP BY t.owner_user_id
22 ORDER BY price DESC 24 ORDER BY price DESC
23 </select> 25 </select>
  26 +
24 <select id="receivablesRanKing" 27 <select id="receivablesRanKing"
25 resultType="cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiReceivablesRanKingRespVO"> 28 resultType="cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiReceivablesRanKingRespVO">
26 SELECT IFNULL(SUM(t.price), 0) AS price, su.nickname, t.owner_user_id, dept.name AS deptName 29 SELECT IFNULL(SUM(t.price), 0) AS price, su.nickname, t.owner_user_id, dept.name AS deptName
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderSaveReqVO.java
1 package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order; 1 package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order;
2 2
3 -import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSalesOrderItemDO;  
4 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
5 import jakarta.validation.constraints.NotEmpty; 4 import jakarta.validation.constraints.NotEmpty;
6 import jakarta.validation.constraints.NotNull; 5 import jakarta.validation.constraints.NotNull;
@@ -30,7 +29,7 @@ public class ErpSaleOrderSaveReqVO { @@ -30,7 +29,7 @@ public class ErpSaleOrderSaveReqVO {
30 private LocalDateTime orderTime; 29 private LocalDateTime orderTime;
31 30
32 @Schema(description = "销售员编号数组") 31 @Schema(description = "销售员编号数组")
33 - private String salePersonIds; 32 + private List<Long> salePersonIds;
34 33
35 @Schema(description = "合计价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "26094") 34 @Schema(description = "合计价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "26094")
36 @NotNull(message = "合计价格,单位:元不能为空") 35 @NotNull(message = "合计价格,单位:元不能为空")
@@ -69,6 +68,61 @@ public class ErpSaleOrderSaveReqVO { @@ -69,6 +68,61 @@ public class ErpSaleOrderSaveReqVO {
69 // private Integer status; 68 // private Integer status;
70 69
71 @Schema(description = "ERP 销售订单明细列表") 70 @Schema(description = "ERP 销售订单明细列表")
72 - private List<ErpSalesOrderItemDO> salesOrderItems; 71 + private List<Item> salesOrderItems;
  72 +
  73 + @Schema(description = "管理后台 - ERP 销售订单明细新增/修改 Request VO")
  74 + @Data
  75 + public class Item {
  76 +
  77 + @Schema(description = "编号", example = "20704")
  78 + private Long id;
  79 +
  80 + // TODO 芋艿:后面删除
  81 +// @Schema(description = "销售订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30765")
  82 +// @NotNull(message = "销售订单编号不能为空")
  83 +// private Long orderId;
  84 +
  85 +// @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "5574")
  86 +// @NotNull(message = "商品 SPU 编号不能为空")
  87 +// private Long productSpuId;
  88 +
  89 + @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21273")
  90 + @NotNull(message = "商品 SKU 编号不能为空")
  91 + private Long productSkuId;
  92 +
  93 + @Schema(description = "商品单位", requiredMode = Schema.RequiredMode.REQUIRED)
  94 + @NotEmpty(message = "商品单位不能为空")
  95 + private String productUnit;
  96 +
  97 + @Schema(description = "商品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "6897")
  98 + @NotNull(message = "商品单价不能为空")
  99 + private BigDecimal productPrice;
  100 +
  101 + @Schema(description = "数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "22100")
  102 + @NotNull(message = "数量不能为空")
  103 + private Integer count;
  104 +
  105 + // TODO 芋艿:后面删除
  106 +// @Schema(description = "总价", requiredMode = Schema.RequiredMode.REQUIRED, example = "26868")
  107 +// @NotNull(message = "总价不能为空")
  108 +// private BigDecimal totalPrice;
  109 +
  110 + @Schema(description = "备注", example = "你说的对")
  111 + private String description;
  112 +
  113 + @Schema(description = "税率,百分比", requiredMode = Schema.RequiredMode.REQUIRED)
  114 + @NotNull(message = "税率,百分比不能为空")
  115 + private BigDecimal taxPercent;
  116 +
  117 + @Schema(description = "税额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "15791")
  118 + @NotNull(message = "税额,单位:元不能为空")
  119 + private BigDecimal taxPrice;
  120 +
  121 + // TODO 芋艿:后面删除
  122 +// @Schema(description = "支付金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "21930")
  123 +// @NotNull(message = "支付金额,单位:元不能为空")
  124 +// private BigDecimal payPrice;
  125 +
  126 + }
73 127
74 } 128 }
75 \ No newline at end of file 129 \ No newline at end of file
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java
@@ -40,11 +40,16 @@ public class ErpSaleOrderServiceImpl implements ErpSaleOrderService { @@ -40,11 +40,16 @@ public class ErpSaleOrderServiceImpl implements ErpSaleOrderService {
40 saleOrderMapper.insert(saleOrder); 40 saleOrderMapper.insert(saleOrder);
41 41
42 // 插入子表 42 // 插入子表
43 - createSalesOrderItemsList(saleOrder.getId(), createReqVO.getSalesOrderItems()); 43 +// createSalesOrderItemsList(saleOrder.getId(), createReqVO.getSalesOrderItems());
44 // 返回 44 // 返回
45 return saleOrder.getId(); 45 return saleOrder.getId();
46 } 46 }
47 47
  48 + private void createSalesOrderItemsList(Long id, List<ErpSalesOrderItemDO> list) {
  49 + list.forEach(o -> o.setId(id));
  50 + salesOrderItemMapper.insertBatch(list);
  51 + }
  52 +
48 @Override 53 @Override
49 @Transactional(rollbackFor = Exception.class) 54 @Transactional(rollbackFor = Exception.class)
50 public void updateSaleOrder(ErpSaleOrderSaveReqVO updateReqVO) { 55 public void updateSaleOrder(ErpSaleOrderSaveReqVO updateReqVO) {
@@ -55,7 +60,13 @@ public class ErpSaleOrderServiceImpl implements ErpSaleOrderService { @@ -55,7 +60,13 @@ public class ErpSaleOrderServiceImpl implements ErpSaleOrderService {
55 saleOrderMapper.updateById(updateObj); 60 saleOrderMapper.updateById(updateObj);
56 61
57 // 更新子表 62 // 更新子表
58 - updateSalesOrderItemsList(updateReqVO.getId(), updateReqVO.getSalesOrderItems()); 63 +// updateSalesOrderItemsList(updateReqVO.getId(), updateReqVO.getSalesOrderItems());
  64 + }
  65 +
  66 + private void updateSalesOrderItemsList(Long id, List<ErpSalesOrderItemDO> list) {
  67 + deleteSalesOrderItemsById(id);
  68 + list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下:1)id 冲突;2)updateTime 不更新
  69 + createSalesOrderItemsList(id, list);
59 } 70 }
60 71
61 @Override 72 @Override
@@ -88,17 +99,6 @@ public class ErpSaleOrderServiceImpl implements ErpSaleOrderService { @@ -88,17 +99,6 @@ public class ErpSaleOrderServiceImpl implements ErpSaleOrderService {
88 99
89 // ==================== 子表(ERP 销售订单明细) ==================== 100 // ==================== 子表(ERP 销售订单明细) ====================
90 101
91 - private void createSalesOrderItemsList(Long id, List<ErpSalesOrderItemDO> list) {  
92 - list.forEach(o -> o.setId(id));  
93 - salesOrderItemMapper.insertBatch(list);  
94 - }  
95 -  
96 - private void updateSalesOrderItemsList(Long id, List<ErpSalesOrderItemDO> list) {  
97 - deleteSalesOrderItemsById(id);  
98 - list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下:1)id 冲突;2)updateTime 不更新  
99 - createSalesOrderItemsList(id, list);  
100 - }  
101 -  
102 private void deleteSalesOrderItemsById(Long id) { 102 private void deleteSalesOrderItemsById(Long id) {
103 salesOrderItemMapper.deleteById(id); 103 salesOrderItemMapper.deleteById(id);
104 } 104 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApiImpl.java
@@ -46,5 +46,4 @@ public class DeptApiImpl implements DeptApi { @@ -46,5 +46,4 @@ public class DeptApiImpl implements DeptApi {
46 return BeanUtils.toBean(childDeptList, DeptRespDTO.class); 46 return BeanUtils.toBean(childDeptList, DeptRespDTO.class);
47 } 47 }
48 48
49 -  
50 } 49 }