Commit 52a68e18388a4c6f5395d500b1a149eb26e2de6a
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 | 3 | Authorization: Bearer {{token}} |
| 4 | 4 | tenant-id: {{adminTenentId}} |
| 5 | 5 | |
| 6 | - | |
| 7 | 6 | ### 回款金额排行榜 |
| 8 | 7 | GET {{baseUrl}}/bi/rank/receivables-ranKing |
| 9 | 8 | Authorization: Bearer {{token}} |
| 10 | 9 | -tenant-id: {{adminTenentId}} |
| 10 | +tenant-id: {{adminTenentId}} | |
| 11 | 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 | 19 | |
| 20 | 20 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 21 | 21 | |
| 22 | +// TODO @anhaohao:写了 swagger 注解,不写注释哈 | |
| 22 | 23 | /** |
| 23 | 24 | * @author anhaohao |
| 24 | 25 | */ |
| ... | ... | @@ -50,4 +51,5 @@ public class BiRankingController { |
| 50 | 51 | public CommonResult<List<BiReceivablesRanKingRespVO>> receivablesRanKing(BiRankReqVO biRankReqVO) { |
| 51 | 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 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | 4 | import lombok.Data; |
| 5 | 5 | |
| 6 | +// TODO @anhaohao:VO 类有 swagger 注解,不写注释哈 | |
| 6 | 7 | /** |
| 7 | 8 | * 管理后台 - BI 排行榜 Response VO |
| 8 | 9 | * |
| ... | ... | @@ -12,13 +13,14 @@ import lombok.Data; |
| 12 | 13 | @Data |
| 13 | 14 | public class BiContractRanKingRespVO { |
| 14 | 15 | |
| 16 | + // TODO @anhaohao:如果一定返回的字段,需要加 requiredMode = Schema.RequiredMode.REQUIRED, 哈 | |
| 15 | 17 | @Schema(description = "金额", example = "1") |
| 16 | 18 | private Integer price; |
| 17 | 19 | |
| 18 | 20 | @Schema(description = "姓名", example = "1") |
| 19 | 21 | private String nickname; |
| 20 | 22 | |
| 21 | - | |
| 22 | 23 | @Schema(description = "部门名称", example = "1") |
| 23 | 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 | 7 | |
| 8 | 8 | import java.util.List; |
| 9 | 9 | |
| 10 | +// TODO @anhaohao:这个类的命名,还是保持和其它一致使用 ReqVO 结尾;例如说,CrmStatisticsCommonParamReqVO | |
| 10 | 11 | /** |
| 11 | 12 | * @author anhaohao |
| 12 | 13 | * bi参数 |
| ... | ... | @@ -25,17 +26,19 @@ public class BiParams extends PageParam { |
| 25 | 26 | @Schema(description = "用户IDs") |
| 26 | 27 | private List<Long> userIds; |
| 27 | 28 | |
| 29 | + // TODO @anhaohao:这个字段,可以融合到 startTime、endTime 里去,交给前端计算哈; | |
| 28 | 30 | @Schema(description = "类型") |
| 29 | 31 | private String type; |
| 30 | 32 | |
| 33 | + // TODO @anhaohao:还是使用 LocalDateTime | |
| 31 | 34 | @Schema(description = "开始时间") |
| 32 | 35 | private String startTime; |
| 33 | 36 | |
| 34 | 37 | @Schema(description = "结束时间") |
| 35 | 38 | private String endTime; |
| 36 | 39 | |
| 40 | + // TODO @anhaohao:这个字段,是不是直接只基于 deptId 和 userId 来判断即可哈? | |
| 37 | 41 | @Schema(description = "0 部门 1员工") |
| 38 | 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 | 15 | @Schema(description = "部门id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| 16 | 16 | private Long deptId; |
| 17 | 17 | |
| 18 | + // TODO @anhaohao:这个字段,参考 BiParams 的 type 建议 | |
| 18 | 19 | @Schema(description = "分析类型(1.今天 2.昨天 3.本周 4.上周 5.本月 6.上月 7.本季度 8.上季度 9.本年 10 上年)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| 19 | 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 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | 4 | import lombok.Data; |
| 5 | 5 | |
| 6 | +// TODO @anhaohao:参考 BiContractRanKingRespVO 的建议 | |
| 6 | 7 | /** |
| 7 | 8 | * 管理后台 - BI 排行榜 Response VO |
| 8 | 9 | * |
| ... | ... | @@ -20,4 +21,5 @@ public class BiReceivablesRanKingRespVO { |
| 20 | 21 | |
| 21 | 22 | @Schema(description = "部门名称", example = "研发部") |
| 22 | 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 | 3 | * 例如说:报表、图表、数据分析等等 |
| 4 | 4 | * <p> |
| 5 | 5 | * 1. Controller URL:以 /bi/ 开头,避免和其它 Module 冲突 |
| 6 | + * | |
| 7 | + * TODO @anhaohao:mall 当时独立拆分一个 statistics 模块的原因,是因为 mall 拆分了多个模块,没有模块适合承接统计的能力,所以独立了。 | |
| 8 | + * TODO crm 因为没有拆分,所以可以直接放在 crm 模块下面;这样,我们可以在 controller/admin 和 service 下,新建一个 bi 包,专门放置统计的代码。 | |
| 6 | 9 | */ |
| 7 | 10 | package cn.iocoder.yudao.module.bi; |
| 8 | 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
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/util/BiTimeUtil.java
yudao-module-crm/yudao-module-bi-biz/src/main/resources/mapper/rank/BiRankingMapper.xml
| ... | ... | @@ -7,6 +7,7 @@ |
| 7 | 7 | resultType="cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiContractRanKingRespVO"> |
| 8 | 8 | SELECT IFNULL(SUM(t.price), 0) AS price, su.nickname, t.owner_user_id, dept.name AS deptName |
| 9 | 9 | FROM crm_contract t |
| 10 | + <!-- TODO @anhaohao:system_users、system_dept 是不是没用到?尽量不连这 2 个表,微服务下会是独立仓库;如果显示需要,可以在 service 读取后拼接; --> | |
| 10 | 11 | LEFT JOIN system_users AS su ON su.id = t.owner_user_id |
| 11 | 12 | LEFT JOIN system_dept AS dept ON dept.id = su.dept_id |
| 12 | 13 | WHERE t.deleted = 0 |
| ... | ... | @@ -17,10 +18,12 @@ |
| 17 | 18 | #{item} |
| 18 | 19 | </foreach> |
| 19 | 20 | </if> |
| 21 | + <!-- TODO @anhaohao:在某个区间的时间,这么做有点浪费性能;一般做法是 beginTime 是开始时间(00:00:00),finalTime 是结束时间(23:59:59),这样实现的; --> | |
| 20 | 22 | AND DATE_FORMAT(t.order_date,'${sqlDateFormat}') between #{beginTime} and #{finalTime} |
| 21 | 23 | GROUP BY t.owner_user_id |
| 22 | 24 | ORDER BY price DESC |
| 23 | 25 | </select> |
| 26 | + | |
| 24 | 27 | <select id="receivablesRanKing" |
| 25 | 28 | resultType="cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiReceivablesRanKingRespVO"> |
| 26 | 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 | 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 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 5 | 4 | import jakarta.validation.constraints.NotEmpty; |
| 6 | 5 | import jakarta.validation.constraints.NotNull; |
| ... | ... | @@ -30,7 +29,7 @@ public class ErpSaleOrderSaveReqVO { |
| 30 | 29 | private LocalDateTime orderTime; |
| 31 | 30 | |
| 32 | 31 | @Schema(description = "销售员编号数组") |
| 33 | - private String salePersonIds; | |
| 32 | + private List<Long> salePersonIds; | |
| 34 | 33 | |
| 35 | 34 | @Schema(description = "合计价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "26094") |
| 36 | 35 | @NotNull(message = "合计价格,单位:元不能为空") |
| ... | ... | @@ -69,6 +68,61 @@ public class ErpSaleOrderSaveReqVO { |
| 69 | 68 | // private Integer status; |
| 70 | 69 | |
| 71 | 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 | 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 | 40 | saleOrderMapper.insert(saleOrder); |
| 41 | 41 | |
| 42 | 42 | // 插入子表 |
| 43 | - createSalesOrderItemsList(saleOrder.getId(), createReqVO.getSalesOrderItems()); | |
| 43 | +// createSalesOrderItemsList(saleOrder.getId(), createReqVO.getSalesOrderItems()); | |
| 44 | 44 | // 返回 |
| 45 | 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 | 53 | @Override |
| 49 | 54 | @Transactional(rollbackFor = Exception.class) |
| 50 | 55 | public void updateSaleOrder(ErpSaleOrderSaveReqVO updateReqVO) { |
| ... | ... | @@ -55,7 +60,13 @@ public class ErpSaleOrderServiceImpl implements ErpSaleOrderService { |
| 55 | 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 | 72 | @Override |
| ... | ... | @@ -88,17 +99,6 @@ public class ErpSaleOrderServiceImpl implements ErpSaleOrderService { |
| 88 | 99 | |
| 89 | 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 | 102 | private void deleteSalesOrderItemsById(Long id) { |
| 103 | 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