mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-31 18:28:43 +08:00 
			
		
		
		
	Merge remote-tracking branch 'yudao/develop' into develop
This commit is contained in:
		| @@ -164,13 +164,6 @@ public class CrmReceivableController { | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     @GetMapping("/check-receivables-count") | ||||
|     @Operation(summary = "获得待审核回款数量") | ||||
|     @PreAuthorize("@ss.hasPermission('crm:receivable:query')") | ||||
|     public CommonResult<Long> getCheckReceivablesCount() { | ||||
|         return success(receivableService.getCheckReceivablesCount(getLoginUserId())); | ||||
|     } | ||||
|  | ||||
|     @PutMapping("/submit") | ||||
|     @Operation(summary = "提交回款审批") | ||||
|     @PreAuthorize("@ss.hasPermission('crm:receivable:update')") | ||||
| @@ -179,4 +172,11 @@ public class CrmReceivableController { | ||||
|         return success(true); | ||||
|     } | ||||
|  | ||||
|     @GetMapping("/audit-count") | ||||
|     @Operation(summary = "获得待审核回款数量") | ||||
|     @PreAuthorize("@ss.hasPermission('crm:receivable:query')") | ||||
|     public CommonResult<Long> getAuditReceivableCount() { | ||||
|         return success(receivableService.getAuditReceivableCount(getLoginUserId())); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -163,13 +163,6 @@ public class CrmReceivablePlanController { | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     @GetMapping("/remind-receivable-plan-count") | ||||
|     @Operation(summary = "获得待回款提醒数量") | ||||
|     @PreAuthorize("@ss.hasPermission('crm:receivable-plan:query')") | ||||
|     public CommonResult<Long> getRemindReceivablesCount() { | ||||
|         return success(receivablePlanService.getRemindReceivablePlanCount(getLoginUserId())); | ||||
|     } | ||||
|  | ||||
|     @GetMapping("/simple-list") | ||||
|     @Operation(summary = "获得回款计划精简列表", description = "获得回款计划精简列表,主要用于前端的下拉选项") | ||||
|     @Parameters({ | ||||
| @@ -187,4 +180,11 @@ public class CrmReceivablePlanController { | ||||
|                 .setPrice(receivablePlan.getPrice()).setReturnType(receivablePlan.getReturnType()))); | ||||
|     } | ||||
|  | ||||
|     @GetMapping("/remind-count") | ||||
|     @Operation(summary = "获得待回款提醒数量") | ||||
|     @PreAuthorize("@ss.hasPermission('crm:receivable-plan:query')") | ||||
|     public CommonResult<Long> getReceivablePlanRemindCount() { | ||||
|         return success(receivablePlanService.getReceivablePlanRemindCount(getLoginUserId())); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -68,16 +68,22 @@ public interface CrmReceivableMapper extends BaseMapperX<CrmReceivableDO> { | ||||
|         return selectJoinList(CrmReceivableDO.class, query); | ||||
|     } | ||||
|  | ||||
|     default Long selectCheckReceivablesCount(Long userId) { | ||||
|     default Long selectCountByAudit(Long userId) { | ||||
|         MPJLambdaWrapperX<CrmReceivableDO> query = new MPJLambdaWrapperX<>(); | ||||
|         // 我负责的 + 非公海 | ||||
|         CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE.getType(), | ||||
|                 CrmReceivableDO::getId, userId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); | ||||
|         // 未提交 or 审核不通过 | ||||
|         query.in(CrmContractDO::getAuditStatus, CrmAuditStatusEnum.DRAFT.getStatus(), CrmAuditStatusEnum.REJECT.getStatus()); | ||||
|         // 未审核 | ||||
|         query.eq(CrmContractDO::getAuditStatus, CrmAuditStatusEnum.PROCESS.getStatus()); | ||||
|         return selectCount(query); | ||||
|     } | ||||
|  | ||||
|     default List<CrmReceivableDO> selectListByContractIdAndStatus(Long contractId, Collection<Integer> auditStatuses) { | ||||
|         return selectList(new LambdaQueryWrapperX<CrmReceivableDO>() | ||||
|                 .eq(CrmReceivableDO::getContractId, contractId) | ||||
|                 .in(CrmReceivableDO::getAuditStatus, auditStatuses)); | ||||
|     } | ||||
|  | ||||
|     default Map<Long, BigDecimal> selectReceivablePriceMapByContractId(Collection<Long> contractIds) { | ||||
|         if (CollUtil.isEmpty(contractIds)) { | ||||
|             return Collections.emptyMap(); | ||||
| @@ -85,7 +91,8 @@ public interface CrmReceivableMapper extends BaseMapperX<CrmReceivableDO> { | ||||
|         // SQL sum 查询 | ||||
|         List<Map<String, Object>> result = selectMaps(new QueryWrapper<CrmReceivableDO>() | ||||
|                 .select("contract_id, SUM(price) AS total_price") | ||||
|                 .eq("audit_status", CrmAuditStatusEnum.APPROVE.getStatus()) | ||||
|                 .in("audit_status", CrmAuditStatusEnum.DRAFT.getStatus(), // 草稿 + 审批中 + 审批通过 | ||||
|                         CrmAuditStatusEnum.PROCESS, CrmAuditStatusEnum.APPROVE.getStatus()) | ||||
|                 .groupBy("contract_id") | ||||
|                 .in("contract_id", contractIds)); | ||||
|         // 获得金额 | ||||
|   | ||||
| @@ -60,19 +60,16 @@ public interface CrmReceivablePlanMapper extends BaseMapperX<CrmReceivablePlanDO | ||||
|         } | ||||
|  | ||||
|         // Backlog: 回款提醒类型 | ||||
|         // TODO: @dhb52 需要配置 提前提醒天数 | ||||
|         int REMIND_DAYS = 20; | ||||
|         LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now()); | ||||
|         LocalDateTime endOfToday = LocalDateTimeUtil.endOfDay(LocalDateTime.now()); | ||||
|         if (CrmReceivablePlanPageReqVO.REMIND_TYPE_NEEDED.equals(pageReqVO.getRemindType())) { // 待回款 | ||||
|             query.isNull(CrmReceivablePlanDO::getReceivableId) | ||||
|                     .between(CrmReceivablePlanDO::getReturnTime, beginOfToday, endOfToday.plusDays(REMIND_DAYS)); | ||||
|             query.isNull(CrmReceivablePlanDO::getReceivableId) // 未回款 | ||||
|                     .lt(CrmReceivablePlanDO::getReturnTime, beginOfToday) // 已逾期 | ||||
|                     .lt(CrmReceivablePlanDO::getRemindTime, beginOfToday); // 今天开始提醒 | ||||
|         } else if (CrmReceivablePlanPageReqVO.REMIND_TYPE_EXPIRED.equals(pageReqVO.getRemindType())) {  // 已逾期 | ||||
|             query.isNull(CrmReceivablePlanDO::getReceivableId) | ||||
|                     .lt(CrmReceivablePlanDO::getReturnTime, endOfToday); | ||||
|             query.isNull(CrmReceivablePlanDO::getReceivableId) // 未回款 | ||||
|                     .ge(CrmReceivablePlanDO::getReturnTime, beginOfToday); // 已逾期 | ||||
|         } else if (CrmReceivablePlanPageReqVO.REMIND_TYPE_RECEIVED.equals(pageReqVO.getRemindType())) { // 已回款 | ||||
|             query.isNotNull(CrmReceivablePlanDO::getReceivableId) | ||||
|                     .between(CrmReceivablePlanDO::getReturnTime, beginOfToday, endOfToday.plusDays(REMIND_DAYS)); | ||||
|             query.isNotNull(CrmReceivablePlanDO::getReceivableId); | ||||
|         } | ||||
|         return selectJoinPage(pageReqVO, CrmReceivablePlanDO.class, query); | ||||
|     } | ||||
| @@ -86,20 +83,16 @@ public interface CrmReceivablePlanMapper extends BaseMapperX<CrmReceivablePlanDO | ||||
|         return selectJoinList(CrmReceivablePlanDO.class, query); | ||||
|     } | ||||
|  | ||||
|     default Long selectRemindReceivablePlanCount(Long userId) { | ||||
|     default Long selectReceivablePlanCountByRemind(Long userId) { | ||||
|         MPJLambdaWrapperX<CrmReceivablePlanDO> query = new MPJLambdaWrapperX<>(); | ||||
|         // 我负责的 + 非公海 | ||||
|         CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType(), | ||||
|                 CrmReceivablePlanDO::getId, userId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); | ||||
|         // TODO: @dhb52 需要配置 提前提醒天数 | ||||
|         int REMIND_DAYS = 20; | ||||
|         // 未回款 + 已逾期 + 今天开始提醒 | ||||
|         LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now()); | ||||
|         LocalDateTime endOfToday = LocalDateTimeUtil.endOfDay(LocalDateTime.now()); | ||||
|         query.isNull(CrmReceivablePlanDO::getReceivableId) | ||||
|                 .between(CrmReceivablePlanDO::getReturnTime, beginOfToday, endOfToday.plusDays(REMIND_DAYS)); | ||||
|         // TODO return_time 小于现在; | ||||
|         // TODO 未回款 | ||||
|         // TODO remind_time 大于现在; | ||||
|         query.isNull(CrmReceivablePlanDO::getReceivableId) // 未回款 | ||||
|                 .lt(CrmReceivablePlanDO::getReturnTime, beginOfToday) // 已逾期 | ||||
|                 .lt(CrmReceivablePlanDO::getRemindTime, beginOfToday); // 今天开始提醒 | ||||
|         return selectCount(query); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| /** | ||||
|  * TODO 芋艿:临时占位,后续可删除 | ||||
|  * 定时任务 | ||||
|  */ | ||||
| package cn.iocoder.yudao.module.crm.job; | ||||
| @@ -222,7 +222,7 @@ public class CrmContractServiceImpl implements CrmContractService { | ||||
|             success = CRM_CONTRACT_DELETE_SUCCESS) | ||||
|     @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) | ||||
|     public void deleteContract(Long id) { | ||||
|         // TODO @合同待定:如果被 CrmReceivableDO 所使用,则不允许删除 | ||||
|         // TODO @puhui999:如果被 CrmReceivableDO 所使用,则不允许删除 | ||||
|         // 校验存在 | ||||
|         CrmContractDO contract = validateContractExists(id); | ||||
|         // 删除 | ||||
|   | ||||
| @@ -170,7 +170,7 @@ public class CrmPermissionServiceImpl implements CrmPermissionService { | ||||
|             throw exception(CRM_PERMISSION_DELETE_FAIL); | ||||
|         } | ||||
|         // 校验操作人是否为负责人 | ||||
|         CrmPermissionDO permission = permissionMapper.selectByBizIdAndUserId(permissions.getFirst().getBizId(), userId); | ||||
|         CrmPermissionDO permission = permissionMapper.selectByBizIdAndUserId(permissions.get(0).getBizId(), userId); | ||||
|         if (permission == null) { | ||||
|             throw exception(CRM_PERMISSION_DELETE_DENIED); | ||||
|         } | ||||
|   | ||||
| @@ -90,6 +90,6 @@ public interface CrmReceivablePlanService { | ||||
|      * @param userId 用户编号 | ||||
|      * @return 提醒数量 | ||||
|      */ | ||||
|     Long getRemindReceivablePlanCount(Long userId); | ||||
|     Long getReceivablePlanRemindCount(Long userId); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -184,8 +184,8 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Long getRemindReceivablePlanCount(Long userId) { | ||||
|         return receivablePlanMapper.selectRemindReceivablePlanCount(userId); | ||||
|     public Long getReceivablePlanRemindCount(Long userId) { | ||||
|         return receivablePlanMapper.selectReceivablePlanCountByRemind(userId); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -110,9 +110,9 @@ public interface CrmReceivableService { | ||||
|      * 获得待审核回款数量 | ||||
|      * | ||||
|      * @param userId 用户编号 | ||||
|      * @return 提醒数量 | ||||
|      * @return 待审批数量 | ||||
|      */ | ||||
|     Long getCheckReceivablesCount(Long userId); | ||||
|     Long getAuditReceivableCount(Long userId); | ||||
|  | ||||
|     /** | ||||
|      * 获得合同已回款金额 Map | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import cn.hutool.core.lang.Assert; | ||||
| import cn.hutool.core.util.ObjUtil; | ||||
| import cn.hutool.core.util.ObjectUtil; | ||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||
| import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||||
| import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||||
| import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; | ||||
| import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; | ||||
| @@ -36,6 +37,7 @@ import org.springframework.transaction.annotation.Transactional; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
|  | ||||
| import java.math.BigDecimal; | ||||
| import java.util.Arrays; | ||||
| import java.util.Collection; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| @@ -85,18 +87,21 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { | ||||
|     @LogRecord(type = CRM_RECEIVABLE_TYPE, subType = CRM_RECEIVABLE_CREATE_SUB_TYPE, bizNo = "{{#receivable.id}}", | ||||
|             success = CRM_RECEIVABLE_CREATE_SUCCESS) | ||||
|     public Long createReceivable(CrmReceivableSaveReqVO createReqVO) { | ||||
|         // 1.1 校验关联数据存在 | ||||
|         // 1.1 校验可回款金额超过上限 | ||||
|         validateReceivablePriceExceedsLimit(createReqVO); | ||||
|         // 1.2 校验关联数据存在 | ||||
|         validateRelationDataExists(createReqVO); | ||||
|         // 1.2 生成回款编号 | ||||
|         // 1.3 生成回款编号 | ||||
|         String no = noRedisDAO.generate(CrmNoRedisDAO.RECEIVABLE_PREFIX); | ||||
|         if (receivableMapper.selectByNo(no) != null) { | ||||
|             throw exception(RECEIVABLE_NO_EXISTS); | ||||
|         } | ||||
|  | ||||
|         // 2. 插入回款 | ||||
|         // 2.1 插入回款 | ||||
|         CrmReceivableDO receivable = BeanUtils.toBean(createReqVO, CrmReceivableDO.class) | ||||
|                 .setNo(no).setAuditStatus(CrmAuditStatusEnum.DRAFT.getStatus()); | ||||
|         receivableMapper.insert(receivable); | ||||
|         // 2.2 | ||||
|  | ||||
|         // 3. 创建数据权限 | ||||
|         permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_RECEIVABLE.getType()) | ||||
| @@ -113,6 +118,22 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { | ||||
|         return receivable.getId(); | ||||
|     } | ||||
|  | ||||
|     private void validateReceivablePriceExceedsLimit(CrmReceivableSaveReqVO reqVO) { | ||||
|         // 1. 计算剩余可退款金额,不包括 reqVO 自身 | ||||
|         CrmContractDO contract = contractService.validateContract(reqVO.getContractId()); | ||||
|         List<CrmReceivableDO> receivables = receivableMapper.selectListByContractIdAndStatus(reqVO.getContractId(), | ||||
|                 Arrays.asList(CrmAuditStatusEnum.APPROVE.getStatus(), CrmAuditStatusEnum.PROCESS.getStatus())); | ||||
|         if (reqVO.getId() != null) { | ||||
|             receivables.removeIf(receivable -> ObjectUtil.equal(receivable.getId(), reqVO.getId())); | ||||
|         } | ||||
|         BigDecimal notReceivablePrice = contract.getTotalPrice().subtract( | ||||
|                 CollectionUtils.getSumValue(receivables, CrmReceivableDO::getPrice, BigDecimal::add, BigDecimal.ZERO)); | ||||
|         // 2. 校验金额是否超过 | ||||
|         if (reqVO.getPrice().compareTo(notReceivablePrice) > 0) { | ||||
|             throw exception(RECEIVABLE_CREATE_FAIL_PRICE_EXCEEDS_LIMIT, notReceivablePrice); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void validateRelationDataExists(CrmReceivableSaveReqVO reqVO) { | ||||
|         if (reqVO.getOwnerUserId() != null) { | ||||
|             adminUserApi.validateUser(reqVO.getOwnerUserId()); // 校验负责人存在 | ||||
| @@ -144,9 +165,11 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { | ||||
|     public void updateReceivable(CrmReceivableSaveReqVO updateReqVO) { | ||||
|         Assert.notNull(updateReqVO.getId(), "回款编号不能为空"); | ||||
|         updateReqVO.setOwnerUserId(null).setCustomerId(null).setContractId(null).setPlanId(null); // 不允许修改的字段 | ||||
|         // 1.1 校验存在 | ||||
|         // 1.1 校验可回款金额超过上限 | ||||
|         validateReceivablePriceExceedsLimit(updateReqVO); | ||||
|         // 1.2 校验存在 | ||||
|         CrmReceivableDO receivable = validateReceivableExists(updateReqVO.getId()); | ||||
|         // 1.2 只有草稿、审批中,可以编辑; | ||||
|         // 1.3 只有草稿、审批中,可以编辑; | ||||
|         if (!ObjectUtils.equalsAny(receivable.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus(), | ||||
|                 CrmAuditStatusEnum.PROCESS.getStatus())) { | ||||
|             throw exception(RECEIVABLE_UPDATE_FAIL_EDITING_PROHIBITED); | ||||
| @@ -189,6 +212,7 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { | ||||
|         if (receivable.getPlanId() != null && receivablePlanService.getReceivablePlan(receivable.getPlanId()) != null) { | ||||
|             throw exception(RECEIVABLE_DELETE_FAIL); | ||||
|         } | ||||
|         // TODO @puhui999:审批通过时,不允许删除; | ||||
|  | ||||
|         // 2. 删除 | ||||
|         receivableMapper.deleteById(id); | ||||
| @@ -256,8 +280,8 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Long getCheckReceivablesCount(Long userId) { | ||||
|         return receivableMapper.selectCheckReceivablesCount(userId); | ||||
|     public Long getAuditReceivableCount(Long userId) { | ||||
|         return receivableMapper.selectCountByAudit(userId); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 puhui999
					puhui999