Commit 2890de8103346e00b0e1434d2f3c8cd96f66b8b2

Authored by YunaiV
1 parent 332eb30b

✨ CRM:完善回款的新增/修改

Showing 17 changed files with 101 additions and 110 deletions
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java
@@ -28,7 +28,6 @@ public interface ErrorCodeConstants { @@ -28,7 +28,6 @@ public interface ErrorCodeConstants {
28 28
29 // ========== 联系人管理 1-020-003-000 ========== 29 // ========== 联系人管理 1-020-003-000 ==========
30 ErrorCode CONTACT_NOT_EXISTS = new ErrorCode(1_020_003_000, "联系人不存在"); 30 ErrorCode CONTACT_NOT_EXISTS = new ErrorCode(1_020_003_000, "联系人不存在");
31 - ErrorCode CONTACT_BUSINESS_LINK_NOT_EXISTS = new ErrorCode(1_020_003_001, "联系人商机关联不存在");  
32 ErrorCode CONTACT_DELETE_FAIL_CONTRACT_LINK_EXISTS = new ErrorCode(1_020_003_002, "联系人已关联合同,不能删除"); 31 ErrorCode CONTACT_DELETE_FAIL_CONTRACT_LINK_EXISTS = new ErrorCode(1_020_003_002, "联系人已关联合同,不能删除");
33 ErrorCode CONTACT_UPDATE_OWNER_USER_FAIL = new ErrorCode(1_020_003_003, "更新联系人负责人失败"); 32 ErrorCode CONTACT_UPDATE_OWNER_USER_FAIL = new ErrorCode(1_020_003_003, "更新联系人负责人失败");
34 33
@@ -38,10 +37,13 @@ public interface ErrorCodeConstants { @@ -38,10 +37,13 @@ public interface ErrorCodeConstants {
38 ErrorCode RECEIVABLE_DELETE_FAIL = new ErrorCode(1_020_004_002, "删除回款失败,原因: 被回款计划所使用,不允许删除"); 37 ErrorCode RECEIVABLE_DELETE_FAIL = new ErrorCode(1_020_004_002, "删除回款失败,原因: 被回款计划所使用,不允许删除");
39 ErrorCode RECEIVABLE_SUBMIT_FAIL_NOT_DRAFT = new ErrorCode(1_020_004_003, "回款提交审核失败,原因:回款没处在未提交状态"); 38 ErrorCode RECEIVABLE_SUBMIT_FAIL_NOT_DRAFT = new ErrorCode(1_020_004_003, "回款提交审核失败,原因:回款没处在未提交状态");
40 ErrorCode RECEIVABLE_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS = new ErrorCode(1_020_004_004, "更新回款审核状态失败,原因:回款不是审核中状态"); 39 ErrorCode RECEIVABLE_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS = new ErrorCode(1_020_004_004, "更新回款审核状态失败,原因:回款不是审核中状态");
  40 + ErrorCode RECEIVABLE_NO_EXISTS = new ErrorCode(1_020_004_005, "生成回款序列号重复,请重试");
  41 + ErrorCode RECEIVABLE_CREATE_FAIL_CONTRACT_NOT_APPROVE = new ErrorCode(1_020_004_006, "创建回款失败,原因:合同不是审核通过状态");
41 42
42 // ========== 回款计划 1-020-005-000 ========== 43 // ========== 回款计划 1-020-005-000 ==========
43 ErrorCode RECEIVABLE_PLAN_NOT_EXISTS = new ErrorCode(1_020_005_000, "回款计划不存在"); 44 ErrorCode RECEIVABLE_PLAN_NOT_EXISTS = new ErrorCode(1_020_005_000, "回款计划不存在");
44 ErrorCode RECEIVABLE_PLAN_UPDATE_FAIL = new ErrorCode(1_020_006_000, "更想回款计划失败,原因:已经有对应的还款"); 45 ErrorCode RECEIVABLE_PLAN_UPDATE_FAIL = new ErrorCode(1_020_006_000, "更想回款计划失败,原因:已经有对应的还款");
  46 + ErrorCode RECEIVABLE_PLAN_EXISTS_RECEIVABLE = new ErrorCode(1_020_006_001, "回款计划已经有对应的回款,不能使用");
45 47
46 // ========== 客户管理 1_020_006_000 ========== 48 // ========== 客户管理 1_020_006_000 ==========
47 ErrorCode CUSTOMER_NOT_EXISTS = new ErrorCode(1_020_006_000, "客户不存在"); 49 ErrorCode CUSTOMER_NOT_EXISTS = new ErrorCode(1_020_006_000, "客户不存在");
@@ -64,10 +66,8 @@ public interface ErrorCodeConstants { @@ -64,10 +66,8 @@ public interface ErrorCodeConstants {
64 // ========== 权限管理 1_020_007_000 ========== 66 // ========== 权限管理 1_020_007_000 ==========
65 ErrorCode CRM_PERMISSION_NOT_EXISTS = new ErrorCode(1_020_007_000, "数据权限不存在"); 67 ErrorCode CRM_PERMISSION_NOT_EXISTS = new ErrorCode(1_020_007_000, "数据权限不存在");
66 ErrorCode CRM_PERMISSION_DENIED = new ErrorCode(1_020_007_001, "{}操作失败,原因:没有权限"); 68 ErrorCode CRM_PERMISSION_DENIED = new ErrorCode(1_020_007_001, "{}操作失败,原因:没有权限");
67 - ErrorCode CRM_PERMISSION_MODEL_NOT_EXISTS = new ErrorCode(1_020_007_002, "{}不存在");  
68 ErrorCode CRM_PERMISSION_MODEL_TRANSFER_FAIL_OWNER_USER_EXISTS = new ErrorCode(1_020_007_003, "{}操作失败,原因:转移对象已经是该负责人"); 69 ErrorCode CRM_PERMISSION_MODEL_TRANSFER_FAIL_OWNER_USER_EXISTS = new ErrorCode(1_020_007_003, "{}操作失败,原因:转移对象已经是该负责人");
69 ErrorCode CRM_PERMISSION_DELETE_FAIL = new ErrorCode(1_020_007_004, "删除数据权限失败,原因:批量删除权限的时候,只能属于同一个 bizId 下"); 70 ErrorCode CRM_PERMISSION_DELETE_FAIL = new ErrorCode(1_020_007_004, "删除数据权限失败,原因:批量删除权限的时候,只能属于同一个 bizId 下");
70 - ErrorCode CRM_PERMISSION_DELETE_FAIL_EXIST_OWNER = new ErrorCode(1_020_007_005, "删除数据权限失败,原因:存在负责人");  
71 ErrorCode CRM_PERMISSION_DELETE_DENIED = new ErrorCode(1_020_007_006, "删除数据权限失败,原因:没有权限"); 71 ErrorCode CRM_PERMISSION_DELETE_DENIED = new ErrorCode(1_020_007_006, "删除数据权限失败,原因:没有权限");
72 ErrorCode CRM_PERMISSION_DELETE_SELF_PERMISSION_FAIL_EXIST_OWNER = new ErrorCode(1_020_007_007, "删除数据权限失败,原因:不能删除负责人"); 72 ErrorCode CRM_PERMISSION_DELETE_SELF_PERMISSION_FAIL_EXIST_OWNER = new ErrorCode(1_020_007_007, "删除数据权限失败,原因:不能删除负责人");
73 ErrorCode CRM_PERMISSION_CREATE_FAIL = new ErrorCode(1_020_007_008, "创建数据权限失败,原因:所加用户已有权限"); 73 ErrorCode CRM_PERMISSION_CREATE_FAIL = new ErrorCode(1_020_007_008, "创建数据权限失败,原因:所加用户已有权限");
@@ -93,7 +93,6 @@ public interface ErrorCodeConstants { @@ -93,7 +93,6 @@ public interface ErrorCodeConstants {
93 ErrorCode BUSINESS_STATUS_NOT_EXISTS = new ErrorCode(1_020_010_003, "商机状态不存在"); 93 ErrorCode BUSINESS_STATUS_NOT_EXISTS = new ErrorCode(1_020_010_003, "商机状态不存在");
94 94
95 // ========== 客户公海规则设置 1_020_012_000 ========== 95 // ========== 客户公海规则设置 1_020_012_000 ==========
96 - ErrorCode CUSTOMER_POOL_CONFIG_NOT_EXISTS_OR_DISABLED = new ErrorCode(1_020_012_000, "客户公海配置不存在或未启用");  
97 ErrorCode CUSTOMER_LIMIT_CONFIG_NOT_EXISTS = new ErrorCode(1_020_012_001, "客户限制配置不存在"); 96 ErrorCode CUSTOMER_LIMIT_CONFIG_NOT_EXISTS = new ErrorCode(1_020_012_001, "客户限制配置不存在");
98 97
99 // ========== 跟进记录 1_020_013_000 ========== 98 // ========== 跟进记录 1_020_013_000 ==========
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java
@@ -175,12 +175,6 @@ public class CrmContractController { @@ -175,12 +175,6 @@ public class CrmContractController {
175 return success(true); 175 return success(true);
176 } 176 }
177 177
178 - /**  
179 - * 构建详细的合同结果  
180 - *  
181 - * @param contractList 原始合同信息  
182 - * @return 细的合同结果  
183 - */  
184 private List<CrmContractRespVO> buildContractDetailList(List<CrmContractDO> contractList) { 178 private List<CrmContractRespVO> buildContractDetailList(List<CrmContractDO> contractList) {
185 if (CollUtil.isEmpty(contractList)) { 179 if (CollUtil.isEmpty(contractList)) {
186 return Collections.emptyList(); 180 return Collections.emptyList();
@@ -239,7 +233,8 @@ public class CrmContractController { @@ -239,7 +233,8 @@ public class CrmContractController {
239 pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); // 不分页 233 pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); // 不分页
240 PageResult<CrmContractDO> pageResult = contractService.getContractPageByCustomerId(pageReqVO); 234 PageResult<CrmContractDO> pageResult = contractService.getContractPageByCustomerId(pageReqVO);
241 return success(convertList(pageResult.getList(), contract -> new CrmContractRespVO() // 只返回 id、name 等精简字段 235 return success(convertList(pageResult.getList(), contract -> new CrmContractRespVO() // 只返回 id、name 等精简字段
242 - .setId(contract.getId()).setName(contract.getName()))); 236 + .setId(contract.getId()).setName(contract.getName()).setAuditStatus(contract.getAuditStatus())
  237 + .setTotalPrice(contract.getTotalPrice()))); // TODO @芋艿:未回款金额
243 } 238 }
244 239
245 } 240 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java
@@ -158,7 +158,6 @@ public class CrmReceivableController { @@ -158,7 +158,6 @@ public class CrmReceivableController {
158 }); 158 });
159 } 159 }
160 160
161 -  
162 @GetMapping("/check-receivables-count") 161 @GetMapping("/check-receivables-count")
163 @Operation(summary = "获得待审核回款数量") 162 @Operation(summary = "获得待审核回款数量")
164 @PreAuthorize("@ss.hasPermission('crm:receivable:query')") 163 @PreAuthorize("@ss.hasPermission('crm:receivable:query')")
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java
@@ -146,7 +146,7 @@ public class CrmReceivablePlanController { @@ -146,7 +146,7 @@ public class CrmReceivablePlanController {
146 // 1.3 获得合同 Map 146 // 1.3 获得合同 Map
147 Map<Long, CrmContractDO> contractMap = contractService.getContractMap( 147 Map<Long, CrmContractDO> contractMap = contractService.getContractMap(
148 convertSet(receivablePlanList, CrmReceivablePlanDO::getContractId)); 148 convertSet(receivablePlanList, CrmReceivablePlanDO::getContractId));
149 - // 1.4 获得还款 Map 149 + // 1.4 获得回款 Map
150 Map<Long, CrmReceivableDO> receivableMap = receivableService.getReceivableMap( 150 Map<Long, CrmReceivableDO> receivableMap = receivableService.getReceivableMap(
151 convertSet(receivablePlanList, CrmReceivablePlanDO::getReceivableId)); 151 convertSet(receivablePlanList, CrmReceivablePlanDO::getReceivableId));
152 // 2. 拼接数据 152 // 2. 拼接数据
@@ -170,19 +170,21 @@ public class CrmReceivablePlanController { @@ -170,19 +170,21 @@ public class CrmReceivablePlanController {
170 return success(receivablePlanService.getRemindReceivablePlanCount(getLoginUserId())); 170 return success(receivablePlanService.getRemindReceivablePlanCount(getLoginUserId()));
171 } 171 }
172 172
173 - // TODO @芋艿:需要看下;  
174 - @GetMapping("/list-all-simple-by-customer") 173 + @GetMapping("/simple-list")
175 @Operation(summary = "获得回款计划精简列表", description = "获得回款计划精简列表,主要用于前端的下拉选项") 174 @Operation(summary = "获得回款计划精简列表", description = "获得回款计划精简列表,主要用于前端的下拉选项")
176 @Parameters({ 175 @Parameters({
177 @Parameter(name = "customerId", description = "客户编号", required = true), 176 @Parameter(name = "customerId", description = "客户编号", required = true),
178 @Parameter(name = "contractId", description = "合同编号", required = true) 177 @Parameter(name = "contractId", description = "合同编号", required = true)
179 }) 178 })
180 @PreAuthorize("@ss.hasPermission('crm:receivable-plan:query')") 179 @PreAuthorize("@ss.hasPermission('crm:receivable-plan:query')")
181 - public CommonResult<List<CrmReceivablePlanRespVO>> getListAllSimpleByCustomer(@RequestParam("customerId") Long customerId,  
182 - @RequestParam("contractId") Long contractId) {  
183 - PageResult<CrmReceivablePlanDO> result = receivablePlanService.getReceivablePlanPageByCustomerId(  
184 - new CrmReceivablePlanPageReqVO().setCustomerId(customerId).setContractId(contractId));  
185 - return success(BeanUtils.toBean(result.getList(), CrmReceivablePlanRespVO.class)); 180 + public CommonResult<List<CrmReceivablePlanRespVO>> getReceivablePlanSimpleList(@RequestParam("customerId") Long customerId,
  181 + @RequestParam("contractId") Long contractId) {
  182 + CrmReceivablePlanPageReqVO pageReqVO = new CrmReceivablePlanPageReqVO().setCustomerId(customerId).setContractId(contractId);
  183 + pageReqVO.setPageNo(PAGE_SIZE_NONE);
  184 + PageResult<CrmReceivablePlanDO> pageResult = receivablePlanService.getReceivablePlanPageByCustomerId(pageReqVO);
  185 + return success(convertList(pageResult.getList(), receivablePlan -> new CrmReceivablePlanRespVO() // 只返回 id、period 等信息
  186 + .setId(receivablePlan.getId()).setPeriod(receivablePlan.getPeriod()).setReceivableId(receivablePlan.getReceivableId())
  187 + .setPrice(receivablePlan.getPrice()).setReturnType(receivablePlan.getReturnType())));
186 } 188 }
187 189
188 } 190 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanRespVO.java
@@ -48,9 +48,6 @@ public class CrmReceivablePlanRespVO { @@ -48,9 +48,6 @@ public class CrmReceivablePlanRespVO {
48 @Schema(description = "回款信息") 48 @Schema(description = "回款信息")
49 private CrmReceivableRespVO receivable; 49 private CrmReceivableRespVO receivable;
50 50
51 - @Schema(description = "完成状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")  
52 - private Boolean finishStatus;  
53 -  
54 @Schema(description = "提前几天提醒", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 51 @Schema(description = "提前几天提醒", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
55 private Integer remindDays; 52 private Integer remindDays;
56 53
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableRespVO.java
@@ -54,11 +54,14 @@ public class CrmReceivableRespVO { @@ -54,11 +54,14 @@ public class CrmReceivableRespVO {
54 @Schema(description = "备注", example = "备注") 54 @Schema(description = "备注", example = "备注")
55 private String remark; 55 private String remark;
56 56
  57 + @Schema(description = "审批状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
  58 + private Integer auditStatus;
  59 +
57 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) 60 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
58 private LocalDateTime createTime; 61 private LocalDateTime createTime;
59 62
60 - @Schema(description = "审批状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")  
61 - private Integer auditStatus; 63 + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
  64 + private LocalDateTime updateTime;
62 65
63 @Schema(description = "创建人", example = "25682") 66 @Schema(description = "创建人", example = "25682")
64 private String creator; 67 private String creator;
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableSaveReqVO.java
@@ -16,11 +16,19 @@ public class CrmReceivableSaveReqVO { @@ -16,11 +16,19 @@ public class CrmReceivableSaveReqVO {
16 @Schema(description = "编号", example = "25787") 16 @Schema(description = "编号", example = "25787")
17 private Long id; 17 private Long id;
18 18
19 - @Schema(description = "回款编号", example = "31177")  
20 - private String no; 19 + @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
  20 + @NotNull(message = "负责人编号不能为空")
  21 + private Long ownerUserId;
21 22
22 - @Schema(description = "回款计划编号", example = "1024")  
23 - private Long planId; // 不是通过回款计划创建的回款没有回款计划编号 23 + @Schema(description = "客户编号", example = "2")
  24 + private Long customerId; // 该字段不通过前端传递,而是 contractId 查询出来设置进去
  25 +
  26 + @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
  27 + @NotNull(message = "合同编号不能为空")
  28 + private Long contractId;
  29 +
  30 + @Schema(description = "回款计划编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  31 + private Long planId;
24 32
25 @Schema(description = "回款方式", example = "2") 33 @Schema(description = "回款方式", example = "2")
26 @InEnum(CrmReceivableReturnTypeEnum.class) 34 @InEnum(CrmReceivableReturnTypeEnum.class)
@@ -30,22 +38,10 @@ public class CrmReceivableSaveReqVO { @@ -30,22 +38,10 @@ public class CrmReceivableSaveReqVO {
30 @NotNull(message = "回款金额不能为空") 38 @NotNull(message = "回款金额不能为空")
31 private BigDecimal price; 39 private BigDecimal price;
32 40
33 - @Schema(description = "计划回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02")  
34 - @NotNull(message = "计划回款日期不能为空") 41 + @Schema(description = "回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02")
  42 + @NotNull(message = "回款日期不能为空")
35 private LocalDateTime returnTime; 43 private LocalDateTime returnTime;
36 44
37 - @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")  
38 - @NotNull(message = "客户编号不能为空")  
39 - private Long customerId;  
40 -  
41 - @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")  
42 - @NotNull(message = "合同编号不能为空")  
43 - private Long contractId;  
44 -  
45 - @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")  
46 - @NotNull(message = "负责人编号不能为空")  
47 - private Long ownerUserId;  
48 -  
49 @Schema(description = "备注", example = "备注") 45 @Schema(description = "备注", example = "备注")
50 private String remark; 46 private String remark;
51 47
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivableDO.java
@@ -39,15 +39,21 @@ public class CrmReceivableDO extends BaseDO { @@ -39,15 +39,21 @@ public class CrmReceivableDO extends BaseDO {
39 */ 39 */
40 private String no; 40 private String no;
41 /** 41 /**
42 - * 回款计划编号,关联 {@link CrmReceivablePlanDO#getId()} 42 + * 回款计划编号
  43 + *
  44 + * 关联 {@link CrmReceivablePlanDO#getId()},非必须
43 */ 45 */
44 private Long planId; 46 private Long planId;
45 /** 47 /**
46 - * 客户编号,关联 {@link CrmCustomerDO#getId()} 48 + * 客户编号
  49 + *
  50 + * 关联 {@link CrmCustomerDO#getId()}
47 */ 51 */
48 private Long customerId; 52 private Long customerId;
49 /** 53 /**
50 - * 合同编号,关联 {@link CrmContractDO#getId()} 54 + * 合同编号
  55 + *
  56 + * 关联 {@link CrmContractDO#getId()}
51 */ 57 */
52 private Long contractId; 58 private Long contractId;
53 /** 59 /**
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivablePlanDO.java
@@ -75,10 +75,6 @@ public class CrmReceivablePlanDO extends BaseDO { @@ -75,10 +75,6 @@ public class CrmReceivablePlanDO extends BaseDO {
75 * 回款编号,关联 {@link CrmReceivableDO#getId()} 75 * 回款编号,关联 {@link CrmReceivableDO#getId()}
76 */ 76 */
77 private Long receivableId; 77 private Long receivableId;
78 - /**  
79 - * 完成状态  
80 - */  
81 - private Boolean finishStatus;  
82 78
83 /** 79 /**
84 * 提前几天提醒 80 * 提前几天提醒
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/package-info.java deleted
1 -/**  
2 - * 回款  
3 - */  
4 -package cn.iocoder.yudao.module.crm.dal.dataobject.receivable;  
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivableMapper.java
@@ -24,6 +24,10 @@ import java.util.List; @@ -24,6 +24,10 @@ import java.util.List;
24 @Mapper 24 @Mapper
25 public interface CrmReceivableMapper extends BaseMapperX<CrmReceivableDO> { 25 public interface CrmReceivableMapper extends BaseMapperX<CrmReceivableDO> {
26 26
  27 + default CrmReceivableDO selectByNo(String no) {
  28 + return selectOne(CrmReceivableDO::getNo, no);
  29 + }
  30 +
27 default PageResult<CrmReceivableDO> selectPageByCustomerId(CrmReceivablePageReqVO reqVO) { 31 default PageResult<CrmReceivableDO> selectPageByCustomerId(CrmReceivablePageReqVO reqVO) {
28 return selectPage(reqVO, new LambdaQueryWrapperX<CrmReceivableDO>() 32 return selectPage(reqVO, new LambdaQueryWrapperX<CrmReceivableDO>()
29 .eq(CrmReceivableDO::getCustomerId, reqVO.getCustomerId()) // 必须传递 33 .eq(CrmReceivableDO::getCustomerId, reqVO.getCustomerId()) // 必须传递
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivablePlanMapper.java
@@ -98,7 +98,7 @@ public interface CrmReceivablePlanMapper extends BaseMapperX&lt;CrmReceivablePlanDO @@ -98,7 +98,7 @@ public interface CrmReceivablePlanMapper extends BaseMapperX&lt;CrmReceivablePlanDO
98 query.isNull(CrmReceivablePlanDO::getReceivableId) 98 query.isNull(CrmReceivablePlanDO::getReceivableId)
99 .between(CrmReceivablePlanDO::getReturnTime, beginOfToday, endOfToday.plusDays(REMIND_DAYS)); 99 .between(CrmReceivablePlanDO::getReturnTime, beginOfToday, endOfToday.plusDays(REMIND_DAYS));
100 // TODO return_time 小于现在; 100 // TODO return_time 小于现在;
101 - // TODO 未还款 101 + // TODO 未回款
102 // TODO remind_time 大于现在; 102 // TODO remind_time 大于现在;
103 return selectCount(query); 103 return selectCount(query);
104 } 104 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/no/CrmNoRedisDAO.java
@@ -25,7 +25,7 @@ public class CrmNoRedisDAO { @@ -25,7 +25,7 @@ public class CrmNoRedisDAO {
25 public static final String CONTRACT_NO_PREFIX = "HT"; 25 public static final String CONTRACT_NO_PREFIX = "HT";
26 26
27 /** 27 /**
28 - * 还款 {@link cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO} 28 + * 回款 {@link cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO}
29 */ 29 */
30 public static final String RECEIVABLE_PREFIX = "HK"; 30 public static final String RECEIVABLE_PREFIX = "HK";
31 31
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanService.java
@@ -38,7 +38,7 @@ public interface CrmReceivablePlanService { @@ -38,7 +38,7 @@ public interface CrmReceivablePlanService {
38 * @param id 编号 38 * @param id 编号
39 * @param receivableId 回款编号 39 * @param receivableId 回款编号
40 */ 40 */
41 - void updateReceivableId(Long id, Long receivableId); 41 + void updateReceivablePlanReceivableId(Long id, Long receivableId);
42 42
43 /** 43 /**
44 * 删除回款计划 44 * 删除回款计划
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java
@@ -65,7 +65,7 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService { @@ -65,7 +65,7 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService {
65 // 1. 校验关联数据是否存在 65 // 1. 校验关联数据是否存在
66 validateRelationDataExists(createReqVO); 66 validateRelationDataExists(createReqVO);
67 67
68 - // 2. 插入还款计划 68 + // 2. 插入回款计划
69 CrmReceivablePlanDO maxPeriodReceivablePlan = receivablePlanMapper.selectMaxPeriodByContractId(createReqVO.getContractId()); 69 CrmReceivablePlanDO maxPeriodReceivablePlan = receivablePlanMapper.selectMaxPeriodByContractId(createReqVO.getContractId());
70 int period = maxPeriodReceivablePlan == null ? 1 : maxPeriodReceivablePlan.getPeriod() + 1; 70 int period = maxPeriodReceivablePlan == null ? 1 : maxPeriodReceivablePlan.getPeriod() + 1;
71 CrmReceivablePlanDO receivablePlan = BeanUtils.toBean(createReqVO, CrmReceivablePlanDO.class).setPeriod(period); 71 CrmReceivablePlanDO receivablePlan = BeanUtils.toBean(createReqVO, CrmReceivablePlanDO.class).setPeriod(period);
@@ -95,12 +95,12 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService { @@ -95,12 +95,12 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService {
95 validateRelationDataExists(updateReqVO); 95 validateRelationDataExists(updateReqVO);
96 // 1.2 校验关联数据是否存在 96 // 1.2 校验关联数据是否存在
97 CrmReceivablePlanDO oldReceivablePlan = validateReceivablePlanExists(updateReqVO.getId()); 97 CrmReceivablePlanDO oldReceivablePlan = validateReceivablePlanExists(updateReqVO.getId());
98 - // 1.3 如果已经有对应的还款,则不允许编辑 98 + // 1.3 如果已经有对应的回款,则不允许编辑
99 if (Objects.nonNull(oldReceivablePlan.getReceivableId())) { 99 if (Objects.nonNull(oldReceivablePlan.getReceivableId())) {
100 throw exception(RECEIVABLE_PLAN_UPDATE_FAIL); 100 throw exception(RECEIVABLE_PLAN_UPDATE_FAIL);
101 } 101 }
102 102
103 - // 2. 更新还款计划 103 + // 2. 更新回款计划
104 CrmReceivablePlanDO updateObj = BeanUtils.toBean(updateReqVO, CrmReceivablePlanDO.class); 104 CrmReceivablePlanDO updateObj = BeanUtils.toBean(updateReqVO, CrmReceivablePlanDO.class);
105 if (updateReqVO.getReturnTime() != null && updateReqVO.getRemindDays() != null) { 105 if (updateReqVO.getReturnTime() != null && updateReqVO.getRemindDays() != null) {
106 updateObj.setRemindTime(updateReqVO.getReturnTime().minusDays(updateReqVO.getRemindDays())); 106 updateObj.setRemindTime(updateReqVO.getReturnTime().minusDays(updateReqVO.getRemindDays()));
@@ -124,13 +124,12 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService { @@ -124,13 +124,12 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService {
124 } 124 }
125 } 125 }
126 126
127 - // TODO @芋艿:优化下这个方法的命名  
128 @Override 127 @Override
129 - public void updateReceivableId(Long id, Long receivableId) { 128 + public void updateReceivablePlanReceivableId(Long id, Long receivableId) {
130 // 校验存在 129 // 校验存在
131 validateReceivablePlanExists(id); 130 validateReceivablePlanExists(id);
132 // 更新回款计划 131 // 更新回款计划
133 - receivablePlanMapper.updateById(new CrmReceivablePlanDO().setReceivableId(receivableId).setFinishStatus(true)); 132 + receivablePlanMapper.updateById(new CrmReceivablePlanDO().setId(id).setReceivableId(receivableId));
134 } 133 }
135 134
136 @Override 135 @Override
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java
@@ -113,12 +113,4 @@ public interface CrmReceivableService { @@ -113,12 +113,4 @@ public interface CrmReceivableService {
113 */ 113 */
114 Long getCheckReceivablesCount(Long userId); 114 Long getCheckReceivablesCount(Long userId);
115 115
116 - /**  
117 - * 根据合同编号,获取合同关联的回款数量  
118 - *  
119 - * @param contractId 合同编号  
120 - * @return 数量  
121 - */  
122 - Long getReceivableCountByContractId(Long contractId);  
123 -  
124 } 116 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java
@@ -13,16 +13,15 @@ import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; @@ -13,16 +13,15 @@ import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
13 import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivablePageReqVO; 13 import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivablePageReqVO;
14 import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableSaveReqVO; 14 import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableSaveReqVO;
15 import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; 15 import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
16 -import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;  
17 import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO; 16 import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO;
18 import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO; 17 import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO;
19 import cn.iocoder.yudao.module.crm.dal.mysql.receivable.CrmReceivableMapper; 18 import cn.iocoder.yudao.module.crm.dal.mysql.receivable.CrmReceivableMapper;
  19 +import cn.iocoder.yudao.module.crm.dal.redis.no.CrmNoRedisDAO;
20 import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; 20 import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum;
21 import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; 21 import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
22 import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; 22 import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
23 import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; 23 import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission;
24 import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; 24 import cn.iocoder.yudao.module.crm.service.contract.CrmContractService;
25 -import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;  
26 import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; 25 import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
27 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; 26 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO;
28 import cn.iocoder.yudao.module.system.api.user.AdminUserApi; 27 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
@@ -55,6 +54,7 @@ import static cn.iocoder.yudao.module.crm.util.CrmAuditStatusUtils.convertBpmRes @@ -55,6 +54,7 @@ import static cn.iocoder.yudao.module.crm.util.CrmAuditStatusUtils.convertBpmRes
55 @Slf4j 54 @Slf4j
56 public class CrmReceivableServiceImpl implements CrmReceivableService { 55 public class CrmReceivableServiceImpl implements CrmReceivableService {
57 56
  57 + // TODO @芋艿:改个名字
58 /** 58 /**
59 * BPM 回款审批流程标识 59 * BPM 回款审批流程标识
60 */ 60 */
@@ -64,9 +64,10 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { @@ -64,9 +64,10 @@ public class CrmReceivableServiceImpl implements CrmReceivableService {
64 private CrmReceivableMapper receivableMapper; 64 private CrmReceivableMapper receivableMapper;
65 65
66 @Resource 66 @Resource
67 - private CrmContractService contractService; 67 + private CrmNoRedisDAO noRedisDAO;
  68 +
68 @Resource 69 @Resource
69 - private CrmCustomerService customerService; 70 + private CrmContractService contractService;
70 @Resource 71 @Resource
71 @Lazy // 延迟加载,避免循环依赖 72 @Lazy // 延迟加载,避免循环依赖
72 private CrmReceivablePlanService receivablePlanService; 73 private CrmReceivablePlanService receivablePlanService;
@@ -83,41 +84,54 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { @@ -83,41 +84,54 @@ public class CrmReceivableServiceImpl implements CrmReceivableService {
83 @LogRecord(type = CRM_RECEIVABLE_TYPE, subType = CRM_RECEIVABLE_CREATE_SUB_TYPE, bizNo = "{{#receivable.id}}", 84 @LogRecord(type = CRM_RECEIVABLE_TYPE, subType = CRM_RECEIVABLE_CREATE_SUB_TYPE, bizNo = "{{#receivable.id}}",
84 success = CRM_RECEIVABLE_CREATE_SUCCESS) 85 success = CRM_RECEIVABLE_CREATE_SUCCESS)
85 public Long createReceivable(CrmReceivableSaveReqVO createReqVO) { 86 public Long createReceivable(CrmReceivableSaveReqVO createReqVO) {
86 - // 1. 校验关联数据存在 87 + // 1.1 校验关联数据存在
87 validateRelationDataExists(createReqVO); 88 validateRelationDataExists(createReqVO);
88 - // 2. 插入还款  
89 - CrmReceivableDO receivable = BeanUtils.toBean(createReqVO, CrmReceivableDO.class).setAuditStatus(CrmAuditStatusEnum.DRAFT.getStatus()); 89 + // 1.2 生成回款编号
  90 + String no = noRedisDAO.generate(CrmNoRedisDAO.RECEIVABLE_PREFIX);
  91 + if (receivableMapper.selectByNo(no) != null) {
  92 + throw exception(RECEIVABLE_NO_EXISTS);
  93 + }
  94 +
  95 + // 2. 插入回款
  96 + CrmReceivableDO receivable = BeanUtils.toBean(createReqVO, CrmReceivableDO.class)
  97 + .setNo(no).setAuditStatus(CrmAuditStatusEnum.DRAFT.getStatus());
90 receivableMapper.insert(receivable); 98 receivableMapper.insert(receivable);
  99 +
91 // 3. 创建数据权限 100 // 3. 创建数据权限
92 permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_RECEIVABLE.getType()) 101 permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_RECEIVABLE.getType())
93 - .setBizId(receivable.getId()).setUserId(createReqVO.getOwnerUserId()).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人 102 + .setBizId(receivable.getId()).setUserId(createReqVO.getOwnerUserId())
  103 + .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人
  104 +
94 // 4. 更新关联的回款计划 105 // 4. 更新关联的回款计划
95 - if (Objects.nonNull(createReqVO.getPlanId())) {  
96 - receivablePlanService.updateReceivableId(receivable.getPlanId(), receivable.getId()); 106 + if (createReqVO.getPlanId() != null) {
  107 + receivablePlanService.updateReceivablePlanReceivableId(receivable.getPlanId(), receivable.getId());
97 } 108 }
  109 +
98 // 5. 记录操作日志上下文 110 // 5. 记录操作日志上下文
99 LogRecordContext.putVariable("receivable", receivable); 111 LogRecordContext.putVariable("receivable", receivable);
100 return receivable.getId(); 112 return receivable.getId();
101 } 113 }
102 114
103 private void validateRelationDataExists(CrmReceivableSaveReqVO reqVO) { 115 private void validateRelationDataExists(CrmReceivableSaveReqVO reqVO) {
104 - adminUserApi.validateUser(reqVO.getOwnerUserId()); // 校验负责人存在  
105 - CrmContractDO contract = contractService.getContract(reqVO.getContractId());  
106 - if (ObjectUtil.isNull(contract)) {  
107 - throw exception(CONTRACT_NOT_EXISTS);  
108 - }  
109 - CrmCustomerDO customer = customerService.getCustomer(reqVO.getCustomerId());  
110 - if (ObjectUtil.isNull(customer)) {  
111 - throw exception(CUSTOMER_NOT_EXISTS); 116 + if (reqVO.getOwnerUserId() != null) {
  117 + adminUserApi.validateUser(reqVO.getOwnerUserId()); // 校验负责人存在
112 } 118 }
113 - if (Objects.isNull(reqVO.getPlanId())) { // 没有回款计划编号则不校验  
114 - return; 119 + if (reqVO.getContractId() != null) {
  120 + CrmContractDO contract = contractService.validateContract(reqVO.getContractId());
  121 + if (ObjectUtil.notEqual(contract.getAuditStatus(), CrmAuditStatusEnum.APPROVE.getStatus())) {
  122 + throw exception(RECEIVABLE_CREATE_FAIL_CONTRACT_NOT_APPROVE);
  123 + }
  124 + reqVO.setCustomerId(contract.getCustomerId()); // 设置客户编号
115 } 125 }
116 - CrmReceivablePlanDO receivablePlan = receivablePlanService.getReceivablePlan(reqVO.getPlanId());  
117 - if (ObjectUtil.isNull(receivablePlan)) {  
118 - throw exception(RECEIVABLE_PLAN_NOT_EXISTS); 126 + if (reqVO.getPlanId() != null) {
  127 + CrmReceivablePlanDO receivablePlan = receivablePlanService.getReceivablePlan(reqVO.getPlanId());
  128 + if (receivablePlan == null) {
  129 + throw exception(RECEIVABLE_PLAN_NOT_EXISTS);
  130 + }
  131 + if (receivablePlan.getReceivableId() != null) {
  132 + throw exception(RECEIVABLE_PLAN_EXISTS_RECEIVABLE);
  133 + }
119 } 134 }
120 -  
121 } 135 }
122 136
123 @Override 137 @Override
@@ -127,6 +141,7 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { @@ -127,6 +141,7 @@ public class CrmReceivableServiceImpl implements CrmReceivableService {
127 @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) 141 @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE)
128 public void updateReceivable(CrmReceivableSaveReqVO updateReqVO) { 142 public void updateReceivable(CrmReceivableSaveReqVO updateReqVO) {
129 Assert.notNull(updateReqVO.getId(), "回款编号不能为空"); 143 Assert.notNull(updateReqVO.getId(), "回款编号不能为空");
  144 + updateReqVO.setOwnerUserId(null).setCustomerId(null).setContractId(null).setPlanId(null); // 不允许修改的字段
130 // 1.1 校验存在 145 // 1.1 校验存在
131 CrmReceivableDO receivable = validateReceivableExists(updateReqVO.getId()); 146 CrmReceivableDO receivable = validateReceivableExists(updateReqVO.getId());
132 // 1.2 只有草稿、审批中,可以编辑; 147 // 1.2 只有草稿、审批中,可以编辑;
@@ -135,7 +150,7 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { @@ -135,7 +150,7 @@ public class CrmReceivableServiceImpl implements CrmReceivableService {
135 throw exception(RECEIVABLE_UPDATE_FAIL_EDITING_PROHIBITED); 150 throw exception(RECEIVABLE_UPDATE_FAIL_EDITING_PROHIBITED);
136 } 151 }
137 152
138 - // 2. 更新还款 153 + // 2. 更新回款
139 CrmReceivableDO updateObj = BeanUtils.toBean(updateReqVO, CrmReceivableDO.class); 154 CrmReceivableDO updateObj = BeanUtils.toBean(updateReqVO, CrmReceivableDO.class);
140 receivableMapper.updateById(updateObj); 155 receivableMapper.updateById(updateObj);
141 156
@@ -160,27 +175,25 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { @@ -160,27 +175,25 @@ public class CrmReceivableServiceImpl implements CrmReceivableService {
160 receivableMapper.updateById(new CrmReceivableDO().setId(id).setAuditStatus(auditStatus)); 175 receivableMapper.updateById(new CrmReceivableDO().setId(id).setAuditStatus(auditStatus));
161 } 176 }
162 177
163 - // TODO @liuhongfeng:缺一个取消回款的接口;只有草稿、审批中可以取消;CrmAuditStatusEnum  
164 -  
165 @Override 178 @Override
166 @Transactional(rollbackFor = Exception.class) 179 @Transactional(rollbackFor = Exception.class)
167 @LogRecord(type = CRM_RECEIVABLE_TYPE, subType = CRM_RECEIVABLE_DELETE_SUB_TYPE, bizNo = "{{#id}}", 180 @LogRecord(type = CRM_RECEIVABLE_TYPE, subType = CRM_RECEIVABLE_DELETE_SUB_TYPE, bizNo = "{{#id}}",
168 success = CRM_RECEIVABLE_DELETE_SUCCESS) 181 success = CRM_RECEIVABLE_DELETE_SUCCESS)
169 @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) 182 @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE, bizId = "#id", level = CrmPermissionLevelEnum.OWNER)
170 public void deleteReceivable(Long id) { 183 public void deleteReceivable(Long id) {
171 - // 校验存在 184 + // 1.1 校验存在
172 CrmReceivableDO receivable = validateReceivableExists(id); 185 CrmReceivableDO receivable = validateReceivableExists(id);
173 - // 如果被 CrmReceivablePlanDO 所使用,则不允许删除 186 + // 1.2 如果被 CrmReceivablePlanDO 所使用,则不允许删除
174 if (Objects.nonNull(receivable.getPlanId()) && receivablePlanService.getReceivablePlan(receivable.getPlanId()) != null) { 187 if (Objects.nonNull(receivable.getPlanId()) && receivablePlanService.getReceivablePlan(receivable.getPlanId()) != null) {
175 throw exception(RECEIVABLE_DELETE_FAIL); 188 throw exception(RECEIVABLE_DELETE_FAIL);
176 } 189 }
177 - // 删除  
178 - receivableMapper.deleteById(id);  
179 190
180 - // 删除数据权限 191 + // 2. 删除
  192 + receivableMapper.deleteById(id);
  193 + // 3. 删除数据权限
181 permissionService.deletePermission(CrmBizTypeEnum.CRM_RECEIVABLE.getType(), id); 194 permissionService.deletePermission(CrmBizTypeEnum.CRM_RECEIVABLE.getType(), id);
182 195
183 - // 记录操作日志上下文 196 + // 4. 记录操作日志上下文
184 LogRecordContext.putVariable("receivable", receivable); 197 LogRecordContext.putVariable("receivable", receivable);
185 } 198 }
186 199
@@ -245,10 +258,4 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { @@ -245,10 +258,4 @@ public class CrmReceivableServiceImpl implements CrmReceivableService {
245 return receivableMapper.selectCheckReceivablesCount(userId); 258 return receivableMapper.selectCheckReceivablesCount(userId);
246 } 259 }
247 260
248 - // TODO @芋艿:不确定这个方法还要不要;  
249 - @Override  
250 - public Long getReceivableCountByContractId(Long contractId) {  
251 - return receivableMapper.selectCount(CrmReceivableDO::getContractId, contractId);  
252 - }  
253 -  
254 } 261 }