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

This commit is contained in:
YunaiV 2024-02-25 18:44:26 +08:00
parent 332eb30b6c
commit 2890de8103
17 changed files with 101 additions and 110 deletions

View File

@ -28,7 +28,6 @@ public interface ErrorCodeConstants {
// ========== 联系人管理 1-020-003-000 ========== // ========== 联系人管理 1-020-003-000 ==========
ErrorCode CONTACT_NOT_EXISTS = new ErrorCode(1_020_003_000, "联系人不存在"); ErrorCode CONTACT_NOT_EXISTS = new ErrorCode(1_020_003_000, "联系人不存在");
ErrorCode CONTACT_BUSINESS_LINK_NOT_EXISTS = new ErrorCode(1_020_003_001, "联系人商机关联不存在");
ErrorCode CONTACT_DELETE_FAIL_CONTRACT_LINK_EXISTS = new ErrorCode(1_020_003_002, "联系人已关联合同,不能删除"); ErrorCode CONTACT_DELETE_FAIL_CONTRACT_LINK_EXISTS = new ErrorCode(1_020_003_002, "联系人已关联合同,不能删除");
ErrorCode CONTACT_UPDATE_OWNER_USER_FAIL = new ErrorCode(1_020_003_003, "更新联系人负责人失败"); ErrorCode CONTACT_UPDATE_OWNER_USER_FAIL = new ErrorCode(1_020_003_003, "更新联系人负责人失败");
@ -38,10 +37,13 @@ public interface ErrorCodeConstants {
ErrorCode RECEIVABLE_DELETE_FAIL = new ErrorCode(1_020_004_002, "删除回款失败,原因: 被回款计划所使用,不允许删除"); ErrorCode RECEIVABLE_DELETE_FAIL = new ErrorCode(1_020_004_002, "删除回款失败,原因: 被回款计划所使用,不允许删除");
ErrorCode RECEIVABLE_SUBMIT_FAIL_NOT_DRAFT = new ErrorCode(1_020_004_003, "回款提交审核失败,原因:回款没处在未提交状态"); ErrorCode RECEIVABLE_SUBMIT_FAIL_NOT_DRAFT = new ErrorCode(1_020_004_003, "回款提交审核失败,原因:回款没处在未提交状态");
ErrorCode RECEIVABLE_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS = new ErrorCode(1_020_004_004, "更新回款审核状态失败,原因:回款不是审核中状态"); ErrorCode RECEIVABLE_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS = new ErrorCode(1_020_004_004, "更新回款审核状态失败,原因:回款不是审核中状态");
ErrorCode RECEIVABLE_NO_EXISTS = new ErrorCode(1_020_004_005, "生成回款序列号重复,请重试");
ErrorCode RECEIVABLE_CREATE_FAIL_CONTRACT_NOT_APPROVE = new ErrorCode(1_020_004_006, "创建回款失败,原因:合同不是审核通过状态");
// ========== 回款计划 1-020-005-000 ========== // ========== 回款计划 1-020-005-000 ==========
ErrorCode RECEIVABLE_PLAN_NOT_EXISTS = new ErrorCode(1_020_005_000, "回款计划不存在"); ErrorCode RECEIVABLE_PLAN_NOT_EXISTS = new ErrorCode(1_020_005_000, "回款计划不存在");
ErrorCode RECEIVABLE_PLAN_UPDATE_FAIL = new ErrorCode(1_020_006_000, "更想回款计划失败,原因:已经有对应的还款"); ErrorCode RECEIVABLE_PLAN_UPDATE_FAIL = new ErrorCode(1_020_006_000, "更想回款计划失败,原因:已经有对应的还款");
ErrorCode RECEIVABLE_PLAN_EXISTS_RECEIVABLE = new ErrorCode(1_020_006_001, "回款计划已经有对应的回款,不能使用");
// ========== 客户管理 1_020_006_000 ========== // ========== 客户管理 1_020_006_000 ==========
ErrorCode CUSTOMER_NOT_EXISTS = new ErrorCode(1_020_006_000, "客户不存在"); ErrorCode CUSTOMER_NOT_EXISTS = new ErrorCode(1_020_006_000, "客户不存在");
@ -64,10 +66,8 @@ public interface ErrorCodeConstants {
// ========== 权限管理 1_020_007_000 ========== // ========== 权限管理 1_020_007_000 ==========
ErrorCode CRM_PERMISSION_NOT_EXISTS = new ErrorCode(1_020_007_000, "数据权限不存在"); ErrorCode CRM_PERMISSION_NOT_EXISTS = new ErrorCode(1_020_007_000, "数据权限不存在");
ErrorCode CRM_PERMISSION_DENIED = new ErrorCode(1_020_007_001, "{}操作失败,原因:没有权限"); ErrorCode CRM_PERMISSION_DENIED = new ErrorCode(1_020_007_001, "{}操作失败,原因:没有权限");
ErrorCode CRM_PERMISSION_MODEL_NOT_EXISTS = new ErrorCode(1_020_007_002, "{}不存在");
ErrorCode CRM_PERMISSION_MODEL_TRANSFER_FAIL_OWNER_USER_EXISTS = new ErrorCode(1_020_007_003, "{}操作失败,原因:转移对象已经是该负责人"); ErrorCode CRM_PERMISSION_MODEL_TRANSFER_FAIL_OWNER_USER_EXISTS = new ErrorCode(1_020_007_003, "{}操作失败,原因:转移对象已经是该负责人");
ErrorCode CRM_PERMISSION_DELETE_FAIL = new ErrorCode(1_020_007_004, "删除数据权限失败,原因:批量删除权限的时候,只能属于同一个 bizId 下"); ErrorCode CRM_PERMISSION_DELETE_FAIL = new ErrorCode(1_020_007_004, "删除数据权限失败,原因:批量删除权限的时候,只能属于同一个 bizId 下");
ErrorCode CRM_PERMISSION_DELETE_FAIL_EXIST_OWNER = new ErrorCode(1_020_007_005, "删除数据权限失败,原因:存在负责人");
ErrorCode CRM_PERMISSION_DELETE_DENIED = new ErrorCode(1_020_007_006, "删除数据权限失败,原因:没有权限"); ErrorCode CRM_PERMISSION_DELETE_DENIED = new ErrorCode(1_020_007_006, "删除数据权限失败,原因:没有权限");
ErrorCode CRM_PERMISSION_DELETE_SELF_PERMISSION_FAIL_EXIST_OWNER = new ErrorCode(1_020_007_007, "删除数据权限失败,原因:不能删除负责人"); ErrorCode CRM_PERMISSION_DELETE_SELF_PERMISSION_FAIL_EXIST_OWNER = new ErrorCode(1_020_007_007, "删除数据权限失败,原因:不能删除负责人");
ErrorCode CRM_PERMISSION_CREATE_FAIL = new ErrorCode(1_020_007_008, "创建数据权限失败,原因:所加用户已有权限"); ErrorCode CRM_PERMISSION_CREATE_FAIL = new ErrorCode(1_020_007_008, "创建数据权限失败,原因:所加用户已有权限");
@ -93,7 +93,6 @@ public interface ErrorCodeConstants {
ErrorCode BUSINESS_STATUS_NOT_EXISTS = new ErrorCode(1_020_010_003, "商机状态不存在"); ErrorCode BUSINESS_STATUS_NOT_EXISTS = new ErrorCode(1_020_010_003, "商机状态不存在");
// ========== 客户公海规则设置 1_020_012_000 ========== // ========== 客户公海规则设置 1_020_012_000 ==========
ErrorCode CUSTOMER_POOL_CONFIG_NOT_EXISTS_OR_DISABLED = new ErrorCode(1_020_012_000, "客户公海配置不存在或未启用");
ErrorCode CUSTOMER_LIMIT_CONFIG_NOT_EXISTS = new ErrorCode(1_020_012_001, "客户限制配置不存在"); ErrorCode CUSTOMER_LIMIT_CONFIG_NOT_EXISTS = new ErrorCode(1_020_012_001, "客户限制配置不存在");
// ========== 跟进记录 1_020_013_000 ========== // ========== 跟进记录 1_020_013_000 ==========

View File

@ -175,12 +175,6 @@ public class CrmContractController {
return success(true); return success(true);
} }
/**
* 构建详细的合同结果
*
* @param contractList 原始合同信息
* @return 细的合同结果
*/
private List<CrmContractRespVO> buildContractDetailList(List<CrmContractDO> contractList) { private List<CrmContractRespVO> buildContractDetailList(List<CrmContractDO> contractList) {
if (CollUtil.isEmpty(contractList)) { if (CollUtil.isEmpty(contractList)) {
return Collections.emptyList(); return Collections.emptyList();
@ -239,7 +233,8 @@ public class CrmContractController {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); // 不分页 pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); // 不分页
PageResult<CrmContractDO> pageResult = contractService.getContractPageByCustomerId(pageReqVO); PageResult<CrmContractDO> pageResult = contractService.getContractPageByCustomerId(pageReqVO);
return success(convertList(pageResult.getList(), contract -> new CrmContractRespVO() // 只返回 idname 等精简字段 return success(convertList(pageResult.getList(), contract -> new CrmContractRespVO() // 只返回 idname 等精简字段
.setId(contract.getId()).setName(contract.getName()))); .setId(contract.getId()).setName(contract.getName()).setAuditStatus(contract.getAuditStatus())
.setTotalPrice(contract.getTotalPrice()))); // TODO @芋艿未回款金额
} }
} }

View File

@ -158,7 +158,6 @@ public class CrmReceivableController {
}); });
} }
@GetMapping("/check-receivables-count") @GetMapping("/check-receivables-count")
@Operation(summary = "获得待审核回款数量") @Operation(summary = "获得待审核回款数量")
@PreAuthorize("@ss.hasPermission('crm:receivable:query')") @PreAuthorize("@ss.hasPermission('crm:receivable:query')")

View File

@ -146,7 +146,7 @@ public class CrmReceivablePlanController {
// 1.3 获得合同 Map // 1.3 获得合同 Map
Map<Long, CrmContractDO> contractMap = contractService.getContractMap( Map<Long, CrmContractDO> contractMap = contractService.getContractMap(
convertSet(receivablePlanList, CrmReceivablePlanDO::getContractId)); convertSet(receivablePlanList, CrmReceivablePlanDO::getContractId));
// 1.4 获得 Map // 1.4 获得 Map
Map<Long, CrmReceivableDO> receivableMap = receivableService.getReceivableMap( Map<Long, CrmReceivableDO> receivableMap = receivableService.getReceivableMap(
convertSet(receivablePlanList, CrmReceivablePlanDO::getReceivableId)); convertSet(receivablePlanList, CrmReceivablePlanDO::getReceivableId));
// 2. 拼接数据 // 2. 拼接数据
@ -170,19 +170,21 @@ public class CrmReceivablePlanController {
return success(receivablePlanService.getRemindReceivablePlanCount(getLoginUserId())); return success(receivablePlanService.getRemindReceivablePlanCount(getLoginUserId()));
} }
// TODO @芋艿需要看下 @GetMapping("/simple-list")
@GetMapping("/list-all-simple-by-customer")
@Operation(summary = "获得回款计划精简列表", description = "获得回款计划精简列表,主要用于前端的下拉选项") @Operation(summary = "获得回款计划精简列表", description = "获得回款计划精简列表,主要用于前端的下拉选项")
@Parameters({ @Parameters({
@Parameter(name = "customerId", description = "客户编号", required = true), @Parameter(name = "customerId", description = "客户编号", required = true),
@Parameter(name = "contractId", description = "合同编号", required = true) @Parameter(name = "contractId", description = "合同编号", required = true)
}) })
@PreAuthorize("@ss.hasPermission('crm:receivable-plan:query')") @PreAuthorize("@ss.hasPermission('crm:receivable-plan:query')")
public CommonResult<List<CrmReceivablePlanRespVO>> getListAllSimpleByCustomer(@RequestParam("customerId") Long customerId, public CommonResult<List<CrmReceivablePlanRespVO>> getReceivablePlanSimpleList(@RequestParam("customerId") Long customerId,
@RequestParam("contractId") Long contractId) { @RequestParam("contractId") Long contractId) {
PageResult<CrmReceivablePlanDO> result = receivablePlanService.getReceivablePlanPageByCustomerId( CrmReceivablePlanPageReqVO pageReqVO = new CrmReceivablePlanPageReqVO().setCustomerId(customerId).setContractId(contractId);
new CrmReceivablePlanPageReqVO().setCustomerId(customerId).setContractId(contractId)); pageReqVO.setPageNo(PAGE_SIZE_NONE);
return success(BeanUtils.toBean(result.getList(), CrmReceivablePlanRespVO.class)); PageResult<CrmReceivablePlanDO> pageResult = receivablePlanService.getReceivablePlanPageByCustomerId(pageReqVO);
return success(convertList(pageResult.getList(), receivablePlan -> new CrmReceivablePlanRespVO() // 只返回 idperiod 等信息
.setId(receivablePlan.getId()).setPeriod(receivablePlan.getPeriod()).setReceivableId(receivablePlan.getReceivableId())
.setPrice(receivablePlan.getPrice()).setReturnType(receivablePlan.getReturnType())));
} }
} }

View File

@ -48,9 +48,6 @@ public class CrmReceivablePlanRespVO {
@Schema(description = "回款信息") @Schema(description = "回款信息")
private CrmReceivableRespVO receivable; private CrmReceivableRespVO receivable;
@Schema(description = "完成状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private Boolean finishStatus;
@Schema(description = "提前几天提醒", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @Schema(description = "提前几天提醒", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer remindDays; private Integer remindDays;

View File

@ -54,11 +54,14 @@ public class CrmReceivableRespVO {
@Schema(description = "备注", example = "备注") @Schema(description = "备注", example = "备注")
private String remark; private String remark;
@Schema(description = "审批状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
private Integer auditStatus;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime; private LocalDateTime createTime;
@Schema(description = "审批状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
private Integer auditStatus; private LocalDateTime updateTime;
@Schema(description = "创建人", example = "25682") @Schema(description = "创建人", example = "25682")
private String creator; private String creator;

View File

@ -16,11 +16,19 @@ public class CrmReceivableSaveReqVO {
@Schema(description = "编号", example = "25787") @Schema(description = "编号", example = "25787")
private Long id; private Long id;
@Schema(description = "回款编号", example = "31177") @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
private String no; @NotNull(message = "负责人编号不能为空")
private Long ownerUserId;
@Schema(description = "回款计划编号", example = "1024") @Schema(description = "客户编号", example = "2")
private Long planId; // 不是通过回款计划创建的回款没有回款计划编号 private Long customerId; // 该字段不通过前端传递而是 contractId 查询出来设置进去
@Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@NotNull(message = "合同编号不能为空")
private Long contractId;
@Schema(description = "回款计划编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long planId;
@Schema(description = "回款方式", example = "2") @Schema(description = "回款方式", example = "2")
@InEnum(CrmReceivableReturnTypeEnum.class) @InEnum(CrmReceivableReturnTypeEnum.class)
@ -30,22 +38,10 @@ public class CrmReceivableSaveReqVO {
@NotNull(message = "回款金额不能为空") @NotNull(message = "回款金额不能为空")
private BigDecimal price; private BigDecimal price;
@Schema(description = "计划回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") @Schema(description = "回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02")
@NotNull(message = "计划回款日期不能为空") @NotNull(message = "回款日期不能为空")
private LocalDateTime returnTime; private LocalDateTime returnTime;
@Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@NotNull(message = "客户编号不能为空")
private Long customerId;
@Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@NotNull(message = "合同编号不能为空")
private Long contractId;
@Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@NotNull(message = "负责人编号不能为空")
private Long ownerUserId;
@Schema(description = "备注", example = "备注") @Schema(description = "备注", example = "备注")
private String remark; private String remark;

View File

@ -39,15 +39,21 @@ public class CrmReceivableDO extends BaseDO {
*/ */
private String no; private String no;
/** /**
* 回款计划编号,关联 {@link CrmReceivablePlanDO#getId()} * 回款计划编号
*
* 关联 {@link CrmReceivablePlanDO#getId()}非必须
*/ */
private Long planId; private Long planId;
/** /**
* 客户编号关联 {@link CrmCustomerDO#getId()} * 客户编号
*
* 关联 {@link CrmCustomerDO#getId()}
*/ */
private Long customerId; private Long customerId;
/** /**
* 合同编号关联 {@link CrmContractDO#getId()} * 合同编号
*
* 关联 {@link CrmContractDO#getId()}
*/ */
private Long contractId; private Long contractId;
/** /**

View File

@ -75,10 +75,6 @@ public class CrmReceivablePlanDO extends BaseDO {
* 回款编号关联 {@link CrmReceivableDO#getId()} * 回款编号关联 {@link CrmReceivableDO#getId()}
*/ */
private Long receivableId; private Long receivableId;
/**
* 完成状态
*/
private Boolean finishStatus;
/** /**
* 提前几天提醒 * 提前几天提醒

View File

@ -1,4 +0,0 @@
/**
* 回款
*/
package cn.iocoder.yudao.module.crm.dal.dataobject.receivable;

View File

@ -24,6 +24,10 @@ import java.util.List;
@Mapper @Mapper
public interface CrmReceivableMapper extends BaseMapperX<CrmReceivableDO> { public interface CrmReceivableMapper extends BaseMapperX<CrmReceivableDO> {
default CrmReceivableDO selectByNo(String no) {
return selectOne(CrmReceivableDO::getNo, no);
}
default PageResult<CrmReceivableDO> selectPageByCustomerId(CrmReceivablePageReqVO reqVO) { default PageResult<CrmReceivableDO> selectPageByCustomerId(CrmReceivablePageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<CrmReceivableDO>() return selectPage(reqVO, new LambdaQueryWrapperX<CrmReceivableDO>()
.eq(CrmReceivableDO::getCustomerId, reqVO.getCustomerId()) // 必须传递 .eq(CrmReceivableDO::getCustomerId, reqVO.getCustomerId()) // 必须传递

View File

@ -98,7 +98,7 @@ public interface CrmReceivablePlanMapper extends BaseMapperX<CrmReceivablePlanDO
query.isNull(CrmReceivablePlanDO::getReceivableId) query.isNull(CrmReceivablePlanDO::getReceivableId)
.between(CrmReceivablePlanDO::getReturnTime, beginOfToday, endOfToday.plusDays(REMIND_DAYS)); .between(CrmReceivablePlanDO::getReturnTime, beginOfToday, endOfToday.plusDays(REMIND_DAYS));
// TODO return_time 小于现在 // TODO return_time 小于现在
// TODO // TODO
// TODO remind_time 大于现在 // TODO remind_time 大于现在
return selectCount(query); return selectCount(query);
} }

View File

@ -25,7 +25,7 @@ public class CrmNoRedisDAO {
public static final String CONTRACT_NO_PREFIX = "HT"; public static final String CONTRACT_NO_PREFIX = "HT";
/** /**
* {@link cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO} * {@link cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO}
*/ */
public static final String RECEIVABLE_PREFIX = "HK"; public static final String RECEIVABLE_PREFIX = "HK";

View File

@ -38,7 +38,7 @@ public interface CrmReceivablePlanService {
* @param id 编号 * @param id 编号
* @param receivableId 回款编号 * @param receivableId 回款编号
*/ */
void updateReceivableId(Long id, Long receivableId); void updateReceivablePlanReceivableId(Long id, Long receivableId);
/** /**
* 删除回款计划 * 删除回款计划

View File

@ -65,7 +65,7 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService {
// 1. 校验关联数据是否存在 // 1. 校验关联数据是否存在
validateRelationDataExists(createReqVO); validateRelationDataExists(createReqVO);
// 2. 插入款计划 // 2. 插入款计划
CrmReceivablePlanDO maxPeriodReceivablePlan = receivablePlanMapper.selectMaxPeriodByContractId(createReqVO.getContractId()); CrmReceivablePlanDO maxPeriodReceivablePlan = receivablePlanMapper.selectMaxPeriodByContractId(createReqVO.getContractId());
int period = maxPeriodReceivablePlan == null ? 1 : maxPeriodReceivablePlan.getPeriod() + 1; int period = maxPeriodReceivablePlan == null ? 1 : maxPeriodReceivablePlan.getPeriod() + 1;
CrmReceivablePlanDO receivablePlan = BeanUtils.toBean(createReqVO, CrmReceivablePlanDO.class).setPeriod(period); CrmReceivablePlanDO receivablePlan = BeanUtils.toBean(createReqVO, CrmReceivablePlanDO.class).setPeriod(period);
@ -95,12 +95,12 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService {
validateRelationDataExists(updateReqVO); validateRelationDataExists(updateReqVO);
// 1.2 校验关联数据是否存在 // 1.2 校验关联数据是否存在
CrmReceivablePlanDO oldReceivablePlan = validateReceivablePlanExists(updateReqVO.getId()); CrmReceivablePlanDO oldReceivablePlan = validateReceivablePlanExists(updateReqVO.getId());
// 1.3 如果已经有对应的则不允许编辑 // 1.3 如果已经有对应的则不允许编辑
if (Objects.nonNull(oldReceivablePlan.getReceivableId())) { if (Objects.nonNull(oldReceivablePlan.getReceivableId())) {
throw exception(RECEIVABLE_PLAN_UPDATE_FAIL); throw exception(RECEIVABLE_PLAN_UPDATE_FAIL);
} }
// 2. 更新款计划 // 2. 更新款计划
CrmReceivablePlanDO updateObj = BeanUtils.toBean(updateReqVO, CrmReceivablePlanDO.class); CrmReceivablePlanDO updateObj = BeanUtils.toBean(updateReqVO, CrmReceivablePlanDO.class);
if (updateReqVO.getReturnTime() != null && updateReqVO.getRemindDays() != null) { if (updateReqVO.getReturnTime() != null && updateReqVO.getRemindDays() != null) {
updateObj.setRemindTime(updateReqVO.getReturnTime().minusDays(updateReqVO.getRemindDays())); updateObj.setRemindTime(updateReqVO.getReturnTime().minusDays(updateReqVO.getRemindDays()));
@ -124,13 +124,12 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService {
} }
} }
// TODO @芋艿优化下这个方法的命名
@Override @Override
public void updateReceivableId(Long id, Long receivableId) { public void updateReceivablePlanReceivableId(Long id, Long receivableId) {
// 校验存在 // 校验存在
validateReceivablePlanExists(id); validateReceivablePlanExists(id);
// 更新回款计划 // 更新回款计划
receivablePlanMapper.updateById(new CrmReceivablePlanDO().setReceivableId(receivableId).setFinishStatus(true)); receivablePlanMapper.updateById(new CrmReceivablePlanDO().setId(id).setReceivableId(receivableId));
} }
@Override @Override

View File

@ -113,12 +113,4 @@ public interface CrmReceivableService {
*/ */
Long getCheckReceivablesCount(Long userId); Long getCheckReceivablesCount(Long userId);
/**
* 根据合同编号获取合同关联的回款数量
*
* @param contractId 合同编号
* @return 数量
*/
Long getReceivableCountByContractId(Long contractId);
} }

View File

@ -13,16 +13,15 @@ import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivablePageReqVO; import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivablePageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableSaveReqVO; import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableSaveReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO; import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO; import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO;
import cn.iocoder.yudao.module.crm.dal.mysql.receivable.CrmReceivableMapper; import cn.iocoder.yudao.module.crm.dal.mysql.receivable.CrmReceivableMapper;
import cn.iocoder.yudao.module.crm.dal.redis.no.CrmNoRedisDAO;
import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum;
import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission;
import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; import cn.iocoder.yudao.module.crm.service.contract.CrmContractService;
import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
@ -55,6 +54,7 @@ import static cn.iocoder.yudao.module.crm.util.CrmAuditStatusUtils.convertBpmRes
@Slf4j @Slf4j
public class CrmReceivableServiceImpl implements CrmReceivableService { public class CrmReceivableServiceImpl implements CrmReceivableService {
// TODO @芋艿改个名字
/** /**
* BPM 回款审批流程标识 * BPM 回款审批流程标识
*/ */
@ -64,9 +64,10 @@ public class CrmReceivableServiceImpl implements CrmReceivableService {
private CrmReceivableMapper receivableMapper; private CrmReceivableMapper receivableMapper;
@Resource @Resource
private CrmContractService contractService; private CrmNoRedisDAO noRedisDAO;
@Resource @Resource
private CrmCustomerService customerService; private CrmContractService contractService;
@Resource @Resource
@Lazy // 延迟加载避免循环依赖 @Lazy // 延迟加载避免循环依赖
private CrmReceivablePlanService receivablePlanService; private CrmReceivablePlanService receivablePlanService;
@ -83,41 +84,54 @@ public class CrmReceivableServiceImpl implements CrmReceivableService {
@LogRecord(type = CRM_RECEIVABLE_TYPE, subType = CRM_RECEIVABLE_CREATE_SUB_TYPE, bizNo = "{{#receivable.id}}", @LogRecord(type = CRM_RECEIVABLE_TYPE, subType = CRM_RECEIVABLE_CREATE_SUB_TYPE, bizNo = "{{#receivable.id}}",
success = CRM_RECEIVABLE_CREATE_SUCCESS) success = CRM_RECEIVABLE_CREATE_SUCCESS)
public Long createReceivable(CrmReceivableSaveReqVO createReqVO) { public Long createReceivable(CrmReceivableSaveReqVO createReqVO) {
// 1. 校验关联数据存在 // 1.1 校验关联数据存在
validateRelationDataExists(createReqVO); validateRelationDataExists(createReqVO);
// 2. 插入还款 // 1.2 生成回款编号
CrmReceivableDO receivable = BeanUtils.toBean(createReqVO, CrmReceivableDO.class).setAuditStatus(CrmAuditStatusEnum.DRAFT.getStatus()); String no = noRedisDAO.generate(CrmNoRedisDAO.RECEIVABLE_PREFIX);
if (receivableMapper.selectByNo(no) != null) {
throw exception(RECEIVABLE_NO_EXISTS);
}
// 2. 插入回款
CrmReceivableDO receivable = BeanUtils.toBean(createReqVO, CrmReceivableDO.class)
.setNo(no).setAuditStatus(CrmAuditStatusEnum.DRAFT.getStatus());
receivableMapper.insert(receivable); receivableMapper.insert(receivable);
// 3. 创建数据权限 // 3. 创建数据权限
permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_RECEIVABLE.getType()) permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_RECEIVABLE.getType())
.setBizId(receivable.getId()).setUserId(createReqVO.getOwnerUserId()).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人 .setBizId(receivable.getId()).setUserId(createReqVO.getOwnerUserId())
.setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人
// 4. 更新关联的回款计划 // 4. 更新关联的回款计划
if (Objects.nonNull(createReqVO.getPlanId())) { if (createReqVO.getPlanId() != null) {
receivablePlanService.updateReceivableId(receivable.getPlanId(), receivable.getId()); receivablePlanService.updateReceivablePlanReceivableId(receivable.getPlanId(), receivable.getId());
} }
// 5. 记录操作日志上下文 // 5. 记录操作日志上下文
LogRecordContext.putVariable("receivable", receivable); LogRecordContext.putVariable("receivable", receivable);
return receivable.getId(); return receivable.getId();
} }
private void validateRelationDataExists(CrmReceivableSaveReqVO reqVO) { private void validateRelationDataExists(CrmReceivableSaveReqVO reqVO) {
adminUserApi.validateUser(reqVO.getOwnerUserId()); // 校验负责人存在 if (reqVO.getOwnerUserId() != null) {
CrmContractDO contract = contractService.getContract(reqVO.getContractId()); adminUserApi.validateUser(reqVO.getOwnerUserId()); // 校验负责人存在
if (ObjectUtil.isNull(contract)) {
throw exception(CONTRACT_NOT_EXISTS);
} }
CrmCustomerDO customer = customerService.getCustomer(reqVO.getCustomerId()); if (reqVO.getContractId() != null) {
if (ObjectUtil.isNull(customer)) { CrmContractDO contract = contractService.validateContract(reqVO.getContractId());
throw exception(CUSTOMER_NOT_EXISTS); if (ObjectUtil.notEqual(contract.getAuditStatus(), CrmAuditStatusEnum.APPROVE.getStatus())) {
throw exception(RECEIVABLE_CREATE_FAIL_CONTRACT_NOT_APPROVE);
}
reqVO.setCustomerId(contract.getCustomerId()); // 设置客户编号
} }
if (Objects.isNull(reqVO.getPlanId())) { // 没有回款计划编号则不校验 if (reqVO.getPlanId() != null) {
return; CrmReceivablePlanDO receivablePlan = receivablePlanService.getReceivablePlan(reqVO.getPlanId());
if (receivablePlan == null) {
throw exception(RECEIVABLE_PLAN_NOT_EXISTS);
}
if (receivablePlan.getReceivableId() != null) {
throw exception(RECEIVABLE_PLAN_EXISTS_RECEIVABLE);
}
} }
CrmReceivablePlanDO receivablePlan = receivablePlanService.getReceivablePlan(reqVO.getPlanId());
if (ObjectUtil.isNull(receivablePlan)) {
throw exception(RECEIVABLE_PLAN_NOT_EXISTS);
}
} }
@Override @Override
@ -127,6 +141,7 @@ public class CrmReceivableServiceImpl implements CrmReceivableService {
@CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE)
public void updateReceivable(CrmReceivableSaveReqVO updateReqVO) { public void updateReceivable(CrmReceivableSaveReqVO updateReqVO) {
Assert.notNull(updateReqVO.getId(), "回款编号不能为空"); Assert.notNull(updateReqVO.getId(), "回款编号不能为空");
updateReqVO.setOwnerUserId(null).setCustomerId(null).setContractId(null).setPlanId(null); // 不允许修改的字段
// 1.1 校验存在 // 1.1 校验存在
CrmReceivableDO receivable = validateReceivableExists(updateReqVO.getId()); CrmReceivableDO receivable = validateReceivableExists(updateReqVO.getId());
// 1.2 只有草稿审批中可以编辑 // 1.2 只有草稿审批中可以编辑
@ -135,7 +150,7 @@ public class CrmReceivableServiceImpl implements CrmReceivableService {
throw exception(RECEIVABLE_UPDATE_FAIL_EDITING_PROHIBITED); throw exception(RECEIVABLE_UPDATE_FAIL_EDITING_PROHIBITED);
} }
// 2. 更新 // 2. 更新
CrmReceivableDO updateObj = BeanUtils.toBean(updateReqVO, CrmReceivableDO.class); CrmReceivableDO updateObj = BeanUtils.toBean(updateReqVO, CrmReceivableDO.class);
receivableMapper.updateById(updateObj); receivableMapper.updateById(updateObj);
@ -160,27 +175,25 @@ public class CrmReceivableServiceImpl implements CrmReceivableService {
receivableMapper.updateById(new CrmReceivableDO().setId(id).setAuditStatus(auditStatus)); receivableMapper.updateById(new CrmReceivableDO().setId(id).setAuditStatus(auditStatus));
} }
// TODO @liuhongfeng缺一个取消回款的接口只有草稿审批中可以取消CrmAuditStatusEnum
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@LogRecord(type = CRM_RECEIVABLE_TYPE, subType = CRM_RECEIVABLE_DELETE_SUB_TYPE, bizNo = "{{#id}}", @LogRecord(type = CRM_RECEIVABLE_TYPE, subType = CRM_RECEIVABLE_DELETE_SUB_TYPE, bizNo = "{{#id}}",
success = CRM_RECEIVABLE_DELETE_SUCCESS) success = CRM_RECEIVABLE_DELETE_SUCCESS)
@CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE, bizId = "#id", level = CrmPermissionLevelEnum.OWNER)
public void deleteReceivable(Long id) { public void deleteReceivable(Long id) {
// 校验存在 // 1.1 校验存在
CrmReceivableDO receivable = validateReceivableExists(id); CrmReceivableDO receivable = validateReceivableExists(id);
// 如果被 CrmReceivablePlanDO 所使用则不允许删除 // 1.2 如果被 CrmReceivablePlanDO 所使用则不允许删除
if (Objects.nonNull(receivable.getPlanId()) && receivablePlanService.getReceivablePlan(receivable.getPlanId()) != null) { if (Objects.nonNull(receivable.getPlanId()) && receivablePlanService.getReceivablePlan(receivable.getPlanId()) != null) {
throw exception(RECEIVABLE_DELETE_FAIL); throw exception(RECEIVABLE_DELETE_FAIL);
} }
// 删除
receivableMapper.deleteById(id);
// 删除数据权限 // 2. 删除
receivableMapper.deleteById(id);
// 3. 删除数据权限
permissionService.deletePermission(CrmBizTypeEnum.CRM_RECEIVABLE.getType(), id); permissionService.deletePermission(CrmBizTypeEnum.CRM_RECEIVABLE.getType(), id);
// 记录操作日志上下文 // 4. 记录操作日志上下文
LogRecordContext.putVariable("receivable", receivable); LogRecordContext.putVariable("receivable", receivable);
} }
@ -245,10 +258,4 @@ public class CrmReceivableServiceImpl implements CrmReceivableService {
return receivableMapper.selectCheckReceivablesCount(userId); return receivableMapper.selectCheckReceivablesCount(userId);
} }
// TODO @芋艿不确定这个方法还要不要
@Override
public Long getReceivableCountByContractId(Long contractId) {
return receivableMapper.selectCount(CrmReceivableDO::getContractId, contractId);
}
} }