From c6b133d9192ffbc270f4be1954c36036602a9714 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Fri, 23 Feb 2024 12:14:56 +0800 Subject: [PATCH] =?UTF-8?q?CRM:=20=E5=AE=8C=E5=96=84=E5=9B=9E=E6=AC=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/crm/enums/ErrorCodeConstants.java | 4 + .../module/crm/enums/LogRecordConstants.java | 2 + .../enums/receivable/CrmReturnTypeEnum.java | 51 +++++++ .../receivable/CrmReceivableController.java | 20 ++- .../vo/plan/CrmReceivablePlanRespVO.java | 27 ++-- .../vo/receivable/CrmReceivableBaseVO.java | 61 -------- .../receivable/CrmReceivableCreateReqVO.java | 12 -- .../vo/receivable/CrmReceivableRespVO.java | 40 +++++- .../vo/receivable/CrmReceivableSaveReqVO.java | 55 +++++++ .../receivable/CrmReceivableUpdateReqVO.java | 18 --- .../receivable/CrmReceivableConvert.java | 8 -- .../receivable/CrmReceivableDO.java | 58 ++++---- .../contract/CrmContractServiceImpl.java | 28 +--- .../receivable/CrmReceivablePlanService.java | 8 ++ .../CrmReceivablePlanServiceImpl.java | 14 +- .../receivable/CrmReceivableService.java | 24 +++- .../receivable/CrmReceivableServiceImpl.java | 136 ++++++++++++------ .../listener/CrmReceivableResultListener.java | 33 +++++ .../module/crm/util/CrmAuditStatusUtils.java | 44 ++++++ 19 files changed, 410 insertions(+), 233 deletions(-) create mode 100644 yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/receivable/CrmReturnTypeEnum.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableBaseVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableCreateReqVO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableSaveReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableUpdateReqVO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/listener/CrmReceivableResultListener.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmAuditStatusUtils.java diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java index 28c3404b18..cc12f849bc 100644 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java +++ b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java @@ -32,6 +32,10 @@ public interface ErrorCodeConstants { // ========== 回款 1-020-004-000 ========== ErrorCode RECEIVABLE_NOT_EXISTS = new ErrorCode(1_020_004_000, "回款不存在"); + ErrorCode RECEIVABLE_UPDATE_FAIL_EDITING_PROHIBITED = new ErrorCode(1_020_004_001, "更新回款失败,原因:禁止编辑"); + ErrorCode RECEIVABLE_DELETE_FAIL = new ErrorCode(1_020_004_002, "删除回款失败,原因: 被回款计划所使用,不允许删除"); + ErrorCode RECEIVABLE_SUBMIT_FAIL_NOT_DRAFT = new ErrorCode(1_020_004_003, "回款提交审核失败,原因:回款没处在未提交状态"); + // ========== 回款计划 1-020-005-000 ========== ErrorCode RECEIVABLE_PLAN_NOT_EXISTS = new ErrorCode(1_020_005_000, "回款计划不存在"); diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java index 1b085b70b0..5a7809c021 100644 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java +++ b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java @@ -140,6 +140,8 @@ public interface LogRecordConstants { String CRM_RECEIVABLE_UPDATE_SUCCESS = "更新了合同【{getContractById{#receivable.contractId}}】的第【{{#receivable.period}}】期回款: {_DIFF{#updateReqVO}}"; String CRM_RECEIVABLE_DELETE_SUB_TYPE = "删除回款"; String CRM_RECEIVABLE_DELETE_SUCCESS = "删除了合同【{getContractById{#receivable.contractId}}】的第【{{#receivable.period}}】期回款"; + String CRM_RECEIVABLE_SUBMIT_SUB_TYPE = "提交回款审批"; + String CRM_RECEIVABLE_SUBMIT_SUCCESS = "提交编号为【{{#receivableNo}}】的回款审批成功"; // ======================= CRM_RECEIVABLE_PLAN 回款计划 ======================= diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/receivable/CrmReturnTypeEnum.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/receivable/CrmReturnTypeEnum.java new file mode 100644 index 0000000000..8aacadce3f --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/receivable/CrmReturnTypeEnum.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.crm.enums.receivable; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * CRM 回款方式枚举 + * + * @author HUIHUI + */ +@Getter +@AllArgsConstructor +public enum CrmReturnTypeEnum implements IntArrayValuable { + + // 支票 + CHECK(1, "支票"), + // 现金 + CASH(2, "现金"), + // 邮政汇款 + POSTAL_REMITTANCE(3, "邮政汇款"), + // 电汇 + TELEGRAPHIC_TRANSFER(4, "电汇"), + // 网上转账 + ONLINE_TRANSFER(5, "网上转账"), + // 支付宝 + ALIPAY(6, "支付宝"), + // 微信支付 + WECHAT_PAY(7, "微信支付"), + // 其他 + OTHER(8, "其它"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmReturnTypeEnum::getType).toArray(); + + /** + * 类型 + */ + private final Integer type; + /** + * 名称 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java index f29bc5139a..5bbaefb5bb 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java @@ -5,12 +5,12 @@ import cn.hutool.core.lang.Assert; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableCreateReqVO; import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivablePageReqVO; import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableUpdateReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableSaveReqVO; import cn.iocoder.yudao.module.crm.convert.receivable.CrmReceivableConvert; import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; @@ -61,14 +61,14 @@ public class CrmReceivableController { @PostMapping("/create") @Operation(summary = "创建回款") @PreAuthorize("@ss.hasPermission('crm:receivable:create')") - public CommonResult createReceivable(@Valid @RequestBody CrmReceivableCreateReqVO createReqVO) { - return success(receivableService.createReceivable(createReqVO, getLoginUserId())); + public CommonResult createReceivable(@Valid @RequestBody CrmReceivableSaveReqVO createReqVO) { + return success(receivableService.createReceivable(createReqVO)); } @PutMapping("/update") @Operation(summary = "更新回款") @PreAuthorize("@ss.hasPermission('crm:receivable:update')") - public CommonResult updateReceivable(@Valid @RequestBody CrmReceivableUpdateReqVO updateReqVO) { + public CommonResult updateReceivable(@Valid @RequestBody CrmReceivableSaveReqVO updateReqVO) { receivableService.updateReceivable(updateReqVO); return success(true); } @@ -88,7 +88,7 @@ public class CrmReceivableController { @PreAuthorize("@ss.hasPermission('crm:receivable:query')") public CommonResult getReceivable(@RequestParam("id") Long id) { CrmReceivableDO receivable = receivableService.getReceivable(id); - return success(CrmReceivableConvert.INSTANCE.convert(receivable)); + return success(BeanUtils.toBean(receivable, CrmReceivableRespVO.class)); } @GetMapping("/page") @@ -152,4 +152,12 @@ public class CrmReceivableController { return success(receivableService.getCheckReceivablesCount(getLoginUserId())); } + @PutMapping("/submit") + @Operation(summary = "提交回款审批") + @PreAuthorize("@ss.hasPermission('crm:receivable:submit')") + public CommonResult submitContract(@RequestParam("id") Long id) { + receivableService.submitReceivable(id, getLoginUserId()); + return success(true); + } + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanRespVO.java index c710333f26..9e6d1a03f4 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanRespVO.java @@ -3,40 +3,41 @@ package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import java.math.BigDecimal; import java.time.LocalDateTime; @Schema(description = "管理后台 - CRM 回款计划 Response VO") @Data public class CrmReceivablePlanRespVO { - @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "25153") + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") private Long id; - @Schema(description = "期数", example = "1") - private Integer period; - - @Schema(description = "回款计划编号", example = "19852") + @Schema(description = "回款编号", example = "19852") private Long receivableId; - @Schema(description = "计划回款金额", example = "29675") - private Integer price; + @Schema(description = "期数", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer period; - @Schema(description = "计划回款日期") + @Schema(description = "计划回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") + private BigDecimal price; + + @Schema(description = "计划回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") private LocalDateTime returnTime; - @Schema(description = "提前几天提醒") + @Schema(description = "提前几天提醒", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer remindDays; - @Schema(description = "提醒日期") + @Schema(description = "提醒日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") private LocalDateTime remindTime; - @Schema(description = "客户名称", example = "18026") + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") private Long customerId; - @Schema(description = "合同编号", example = "3473") + @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") private Long contractId; - @Schema(description = "负责人编号", example = "17828") + @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") private Long ownerUserId; @Schema(description = "显示顺序") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableBaseVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableBaseVO.java deleted file mode 100644 index c32bc9ad52..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableBaseVO.java +++ /dev/null @@ -1,61 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable; - -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import org.springframework.format.annotation.DateTimeFormat; - -import java.time.LocalDateTime; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; - -/** - * 回款 Base VO,提供给添加、修改、详细的子 VO 使用 - * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 - */ -@Data -public class CrmReceivableBaseVO { - - @Schema(description = "回款编号",requiredMode = Schema.RequiredMode.REQUIRED, example = "31177") - private String no; - - // TODO @liuhongfeng:回款计划编号 - @Schema(description = "回款计划", example = "31177") - private Long planId; - - // TODO @liuhongfeng:客户编号 - @Schema(description = "客户名称", example = "4963") - private Long customerId; - - // TODO @liuhongfeng:客户编号 - @Schema(description = "合同名称", example = "30305") - private Long contractId; - - // TODO @liuhongfeng:这个字段,应该不是前端传递的噢,而是后端自己生成的 - @Schema(description = "审批状态", example = "1") - @InEnum(CrmAuditStatusEnum.class) - private Integer checkStatus; - - @Schema(description = "回款日期") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime returnTime; - - @Schema(description = "回款方式", example = "2") - private Integer returnType; - - @Schema(description = "回款金额,单位:分", example = "31859") - private Integer price; - - // TODO @liuhongfeng:负责人编号 - @Schema(description = "负责人", example = "22202") - private Long ownerUserId; - - @Schema(description = "显示顺序") - private Integer sort; - - @Schema(description = "备注", example = "备注") - private String remark; - - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableCreateReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableCreateReqVO.java deleted file mode 100644 index 4471b780a8..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableCreateReqVO.java +++ /dev/null @@ -1,12 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable; - -import lombok.*; -import io.swagger.v3.oas.annotations.media.Schema; - -@Schema(description = "管理后台 - CRM 回款创建 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class CrmReceivableCreateReqVO extends CrmReceivableBaseVO { - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableRespVO.java index 7c536bd512..2bb721b460 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableRespVO.java @@ -1,19 +1,49 @@ package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; +import lombok.Data; + +import java.math.BigDecimal; import java.time.LocalDateTime; // TODO 芋艿:导出的 VO,可以考虑使用 @Excel 注解,实现导出功能 @Schema(description = "管理后台 - CRM 回款 Response VO") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class CrmReceivableRespVO extends CrmReceivableBaseVO { +public class CrmReceivableRespVO { - @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "25787") + @Schema(description = "编号", example = "25787") private Long id; + @Schema(description = "回款编号", example = "31177") + private String no; + + @Schema(description = "回款计划编号", example = "1024") + private Long planId; + + @Schema(description = "回款方式", example = "2") + private Integer returnType; + + @Schema(description = "回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") + private BigDecimal price; + + @Schema(description = "计划回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") + private LocalDateTime returnTime; + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Long customerId; + + @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Long contractId; + + @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Long ownerUserId; + + @Schema(description = "显示顺序") + private Integer sort; + + @Schema(description = "备注", example = "备注") + private String remark; + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime createTime; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableSaveReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableSaveReqVO.java new file mode 100644 index 0000000000..5340b43199 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableSaveReqVO.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.crm.enums.receivable.CrmReturnTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - CRM 回款新增/修改 Request VO") +@Data +public class CrmReceivableSaveReqVO { + + @Schema(description = "编号", example = "25787") + private Long id; + + @Schema(description = "回款编号", example = "31177") + private String no; + + @Schema(description = "回款计划编号", example = "1024") + private Long planId; // 不是通过回款计划创建的回款没有回款计划编号 + + @Schema(description = "回款方式", example = "2") + @InEnum(CrmReturnTypeEnum.class) + private Integer returnType; + + @Schema(description = "回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") + @NotNull(message = "回款金额不能为空") + private BigDecimal price; + + @Schema(description = "计划回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") + @NotNull(message = "计划回款日期不能为空") + 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 = "显示顺序") + private Integer sort; + + @Schema(description = "备注", example = "备注") + private String remark; + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableUpdateReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableUpdateReqVO.java deleted file mode 100644 index 0f63978c81..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableUpdateReqVO.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; - -import jakarta.validation.constraints.*; - -@Schema(description = "管理后台 - CRM 回款更新 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class CrmReceivableUpdateReqVO extends CrmReceivableBaseVO { - - @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "25787") - @NotNull(message = "ID不能为空") - private Long id; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/receivable/CrmReceivableConvert.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/receivable/CrmReceivableConvert.java index 3b0c23aae1..d53d14fda0 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/receivable/CrmReceivableConvert.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/receivable/CrmReceivableConvert.java @@ -2,9 +2,7 @@ package cn.iocoder.yudao.module.crm.convert.receivable; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableCreateReqVO; import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableUpdateReqVO; 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; @@ -28,12 +26,6 @@ public interface CrmReceivableConvert { CrmReceivableConvert INSTANCE = Mappers.getMapper(CrmReceivableConvert.class); - CrmReceivableDO convert(CrmReceivableCreateReqVO bean); - - CrmReceivableDO convert(CrmReceivableUpdateReqVO bean); - - CrmReceivableRespVO convert(CrmReceivableDO bean); - default PageResult convertPage(PageResult pageResult, Map userMap, List customerList, List contractList) { PageResult voPageResult = BeanUtils.toBean(pageResult, CrmReceivableRespVO.class); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivableDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivableDO.java index 842fc96b4f..6c1610935d 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivableDO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivableDO.java @@ -2,11 +2,16 @@ package cn.iocoder.yudao.module.crm.dal.dataobject.receivable; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 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.enums.common.CrmAuditStatusEnum; +import cn.iocoder.yudao.module.crm.enums.receivable.CrmReturnTypeEnum; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; +import java.math.BigDecimal; import java.time.LocalDateTime; /** @@ -33,64 +38,55 @@ public class CrmReceivableDO extends BaseDO { * 回款编号 */ private String no; - // TODO @liuhongfeng:“对应实体”,参考别的模块,关联 {@link TableField.MetaInfo#getJdbcType()} /** - * 回款计划 - * - * TODO @liuhongfeng:这个字段什么时候更新,也可以写下 - * - * 对应实体 {@link CrmReceivablePlanDO} + * 回款计划编号,关联 {@link CrmReceivablePlanDO#getId()} */ private Long planId; /** - * 客户 ID - * - * 对应实体 {@link cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO} + * 客户编号,关联 {@link CrmCustomerDO#getId()} */ private Long customerId; /** - * 合同 ID - * - * 对应实体 {@link CrmContractDO} + * 合同编号,关联 {@link CrmContractDO#getId()} */ private Long contractId; /** - * 工作流编号 - * - * TODO @liuhongfeng:这个字段,后续要写下关联的实体哈 + * 负责人编号,关联 {@link AdminUserRespDTO#getId()} */ - private Long processInstanceId; + private Long ownerUserId; + /** * 回款日期 */ private LocalDateTime returnTime; - // TODO @liuhongfeng:少个枚举 /** - * 回款方式 + * 回款方式,关联枚举{@link CrmReturnTypeEnum} */ private Integer returnType; /** - * 回款金额 + * 计划回款金额,单位:元 */ - private Integer price; - // TODO @liuhongfeng:少关联实体; - /** - * 负责人 - */ - private Long ownerUserId; + private BigDecimal price; /** * 显示顺序 */ private Integer sort; - /** - * 审核状态 - * - * 枚举 {@link cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum} - */ - private Integer auditStatus; /** * 备注 */ private String remark; + /** + * 工作流编号 + * + * 关联 ProcessInstance 的 id 属性 + */ + private String processInstanceId; + /** + * 审批状态 + * + * 枚举 {@link CrmAuditStatusEnum} + */ + private Integer auditStatus; + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java index 58e00a53bd..211cec6906 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java @@ -11,7 +11,6 @@ import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.module.bpm.api.listener.dto.BpmResultListenerRespDTO; import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; -import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageReqVO; import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractSaveReqVO; import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTransferReqVO; @@ -50,6 +49,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; +import static cn.iocoder.yudao.module.crm.util.CrmAuditStatusUtils.convertAuditStatus; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_NOT_EXISTS; /** @@ -284,36 +284,12 @@ public class CrmContractServiceImpl implements CrmContractService { @Override public void updateContractAuditStatus(BpmResultListenerRespDTO event) { - // 判断下状态是否符合预期 - if (!isEndResult(event.getResult())) { - return; - } - // 状态转换 - if (ObjUtil.equal(event.getResult(), BpmProcessInstanceResultEnum.APPROVE.getResult())) { - event.setResult(CrmAuditStatusEnum.APPROVE.getStatus()); - } - if (ObjUtil.equal(event.getResult(), BpmProcessInstanceResultEnum.REJECT.getResult())) { - event.setResult(CrmAuditStatusEnum.REJECT.getStatus()); - } - if (ObjUtil.equal(event.getResult(), BpmProcessInstanceResultEnum.CANCEL.getResult())) { - event.setResult(CrmAuditStatusEnum.CANCEL.getStatus()); - } + convertAuditStatus(event); // 更新合同状态 contractMapper.updateById(new CrmContractDO().setId(Long.parseLong(event.getBusinessKey())) .setAuditStatus(event.getResult())); } - /** - * 判断该结果是否处于 End 最终结果 - * - * @param result 结果 - * @return 是否 - */ - public static boolean isEndResult(Integer result) { - return ObjectUtils.equalsAny(result, BpmProcessInstanceResultEnum.APPROVE.getResult(), - BpmProcessInstanceResultEnum.REJECT.getResult(), BpmProcessInstanceResultEnum.CANCEL.getResult()); - } - //======================= 查询相关 ======================= @Override diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanService.java index a67c91c480..7f5854b441 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanService.java @@ -32,6 +32,14 @@ public interface CrmReceivablePlanService { */ void updateReceivablePlan(@Valid CrmReceivablePlanSaveReqVO updateReqVO); + /** + * 更新回款计划关联的回款编号 + * + * @param id 编号 + * @param receivableId 回款编号 + */ + void updateReceivableId(Long id, Long receivableId); + /** * 删除回款计划 * diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java index 3ac3859984..db8ea9e0c4 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java @@ -66,7 +66,7 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService { success = CRM_RECEIVABLE_PLAN_CREATE_SUCCESS) public Long createReceivablePlan(CrmReceivablePlanSaveReqVO createReqVO) { // 1.1 校验关联数据是否存在 - checkReceivablePlan(createReqVO); + validateRelationDataExists(createReqVO); // 1.2 查验关联合同回款数量 Long count = receivableService.getReceivableCountByContractId(createReqVO.getContractId()); int period = (int) (count + 1); @@ -92,7 +92,7 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService { @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE_PLAN, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) public void updateReceivablePlan(CrmReceivablePlanSaveReqVO updateReqVO) { // 1. 校验存在 - checkReceivablePlan(updateReqVO); + validateRelationDataExists(updateReqVO); CrmReceivablePlanDO oldReceivablePlan = validateReceivablePlanExists(updateReqVO.getId()); if (Objects.nonNull(oldReceivablePlan.getReceivableId())) { // 如果已经有对应的还款,则不允许编辑; throw exception(RECEIVABLE_PLAN_UPDATE_FAIL, "已经有对应的还款"); @@ -107,7 +107,15 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService { LogRecordContext.putVariable("receivablePlan", oldReceivablePlan); } - private void checkReceivablePlan(CrmReceivablePlanSaveReqVO reqVO) { + @Override + public void updateReceivableId(Long id, Long receivableId) { + // 校验存在 + validateReceivablePlanExists(id); + // 更新回款计划 + receivablePlanMapper.updateById(new CrmReceivablePlanDO().setReceivableId(receivableId).setFinishStatus(true)); + } + + private void validateRelationDataExists(CrmReceivablePlanSaveReqVO reqVO) { adminUserApi.validateUser(reqVO.getOwnerUserId()); // 校验负责人存在 CrmContractDO contract = contractService.getContract(reqVO.getContractId()); if (ObjectUtil.isNull(contract)) { // 合同不存在 diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java index 808b2cc2e5..7b7d7599d4 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java @@ -1,9 +1,9 @@ package cn.iocoder.yudao.module.crm.service.receivable; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableCreateReqVO; +import cn.iocoder.yudao.module.bpm.api.listener.dto.BpmResultListenerRespDTO; import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivablePageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableUpdateReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableSaveReqVO; import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO; import jakarta.validation.Valid; @@ -22,17 +22,23 @@ public interface CrmReceivableService { * 创建回款 * * @param createReqVO 创建信息 - * @param userId 用户编号 * @return 编号 */ - Long createReceivable(@Valid CrmReceivableCreateReqVO createReqVO, Long userId); + Long createReceivable(@Valid CrmReceivableSaveReqVO createReqVO); /** * 更新回款 * * @param updateReqVO 更新信息 */ - void updateReceivable(@Valid CrmReceivableUpdateReqVO updateReqVO); + void updateReceivable(@Valid CrmReceivableSaveReqVO updateReqVO); + + /** + * 更新回款流程审批结果 + * + * @param event 审批结果 + */ + void updateReceivableAuditStatus(BpmResultListenerRespDTO event); /** * 删除回款 @@ -41,6 +47,14 @@ public interface CrmReceivableService { */ void deleteReceivable(Long id); + /** + * 发起回款审批流程 + * + * @param id 回款编号 + * @param userId 用户编号 + */ + void submitReceivable(Long id, Long userId); + /** * 获得回款 * diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java index 93ad4c97eb..0d26cf3b79 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java @@ -2,14 +2,17 @@ package cn.iocoder.yudao.module.crm.service.receivable; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ObjectUtil; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableCreateReqVO; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.module.bpm.api.listener.dto.BpmResultListenerRespDTO; +import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; +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.CrmReceivableUpdateReqVO; -import cn.iocoder.yudao.module.crm.convert.receivable.CrmReceivableConvert; +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.customer.CrmCustomerDO; import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO; @@ -23,19 +26,23 @@ 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.bo.CrmPermissionCreateReqBO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import com.mzt.logapi.context.LogRecordContext; import com.mzt.logapi.service.impl.DiffParseFunction; import com.mzt.logapi.starter.annotation.LogRecord; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.Collection; import java.util.List; +import java.util.Objects; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; +import static cn.iocoder.yudao.module.crm.util.CrmAuditStatusUtils.convertAuditStatus; /** * CRM 回款 Service 实现类 @@ -46,6 +53,11 @@ import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; @Validated public class CrmReceivableServiceImpl implements CrmReceivableService { + /** + * BPM 回款审批流程标识 + */ + public static final String RECEIVABLE_APPROVE = "receivable-approve"; + @Resource private CrmReceivableMapper receivableMapper; @@ -57,51 +69,47 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { private CrmReceivablePlanService receivablePlanService; @Resource private CrmPermissionService permissionService; + @Resource + private AdminUserApi adminUserApi; + @Resource + private BpmProcessInstanceApi bpmProcessInstanceApi; @Override + @Transactional(rollbackFor = Exception.class) @LogRecord(type = CRM_RECEIVABLE_TYPE, subType = CRM_RECEIVABLE_CREATE_SUB_TYPE, bizNo = "{{#receivable.id}}", success = CRM_RECEIVABLE_CREATE_SUCCESS) - public Long createReceivable(CrmReceivableCreateReqVO createReqVO, Long userId) { - // 插入还款 - CrmReceivableDO receivable = CrmReceivableConvert.INSTANCE.convert(createReqVO); - if (ObjectUtil.isNull(receivable.getAuditStatus())) { - receivable.setAuditStatus(CommonStatusEnum.ENABLE.getStatus()); - } - receivable.setAuditStatus(CrmAuditStatusEnum.DRAFT.getStatus()); - - // TODO @liuhongfeng:一般来说,逻辑的写法,是要先检查,后操作 db;所以,你这个 check 应该放到 CrmReceivableDO receivable 之前; - checkReceivable(receivable); - + public Long createReceivable(CrmReceivableSaveReqVO createReqVO) { + // 1. 校验关联数据存在 + validateRelationDataExists(createReqVO); + // 2. 插入还款 + CrmReceivableDO receivable = BeanUtils.toBean(createReqVO, CrmReceivableDO.class).setAuditStatus(CrmAuditStatusEnum.DRAFT.getStatus()); receivableMapper.insert(receivable); // 3. 创建数据权限 permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_RECEIVABLE.getType()) - .setBizId(receivable.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人 - // TODO @liuhongfeng:需要更新关联的 plan - - // 4. 记录操作日志上下文 + .setBizId(receivable.getId()).setUserId(createReqVO.getOwnerUserId()).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人 + // 4. 更新关联的回款计划 + if (Objects.nonNull(createReqVO.getPlanId())) { + receivablePlanService.updateReceivableId(receivable.getPlanId(), receivable.getId()); + } + // 5. 记录操作日志上下文 LogRecordContext.putVariable("receivable", receivable); return receivable.getId(); } - // TODO @liuhongfeng:这里的括号要注意排版; - private void checkReceivable(CrmReceivableDO receivable) { - // TODO @liuhongfeng:校验 no 的唯一性 - // TODO @liuhongfeng:这个放在参数校验合适 - if (ObjectUtil.isNull(receivable.getContractId())) { - throw exception(CONTRACT_NOT_EXISTS); - } - - CrmContractDO contract = contractService.getContract(receivable.getContractId()); + private void validateRelationDataExists(CrmReceivableSaveReqVO reqVO) { + adminUserApi.validateUser(reqVO.getOwnerUserId()); // 校验负责人存在 + CrmContractDO contract = contractService.getContract(reqVO.getContractId()); if (ObjectUtil.isNull(contract)) { throw exception(CONTRACT_NOT_EXISTS); } - - CrmCustomerDO customer = customerService.getCustomer(receivable.getCustomerId()); + CrmCustomerDO customer = customerService.getCustomer(reqVO.getCustomerId()); if (ObjectUtil.isNull(customer)) { throw exception(CUSTOMER_NOT_EXISTS); } - - CrmReceivablePlanDO receivablePlan = receivablePlanService.getReceivablePlan(receivable.getPlanId()); + if (Objects.isNull(reqVO.getPlanId())) { // 没有回款计划编号则不校验 + return; + } + CrmReceivablePlanDO receivablePlan = receivablePlanService.getReceivablePlan(reqVO.getPlanId()); if (ObjectUtil.isNull(receivablePlan)) { throw exception(RECEIVABLE_PLAN_NOT_EXISTS); } @@ -109,46 +117,84 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { } @Override + @Transactional(rollbackFor = Exception.class) @LogRecord(type = CRM_RECEIVABLE_TYPE, subType = CRM_RECEIVABLE_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", success = CRM_RECEIVABLE_UPDATE_SUCCESS) @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) - public void updateReceivable(CrmReceivableUpdateReqVO updateReqVO) { - // 校验存在 - CrmReceivableDO oldReceivable = validateReceivableExists(updateReqVO.getId()); - // TODO @liuhongfeng:只有在草稿、审核中,可以提交修改 + public void updateReceivable(CrmReceivableSaveReqVO updateReqVO) { + Assert.notNull(updateReqVO.getId(), "回款编号不能为空"); + // 1.1 校验存在 + CrmReceivableDO receivable = validateReceivableExists(updateReqVO.getId()); + // 1.2 只有草稿、审批中,可以编辑; + if (!ObjectUtils.equalsAny(receivable.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus(), + CrmAuditStatusEnum.PROCESS.getStatus())) { + throw exception(RECEIVABLE_UPDATE_FAIL_EDITING_PROHIBITED); + } - // 更新还款 - CrmReceivableDO updateObj = CrmReceivableConvert.INSTANCE.convert(updateReqVO); + // 2. 更新还款 + CrmReceivableDO updateObj = BeanUtils.toBean(updateReqVO, CrmReceivableDO.class); receivableMapper.updateById(updateObj); - // TODO @liuhongfeng:需要更新关联的 plan // 3. 记录操作日志上下文 - LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldReceivable, CrmReceivableUpdateReqVO.class)); - LogRecordContext.putVariable("receivable", oldReceivable); + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(receivable, CrmReceivableSaveReqVO.class)); + LogRecordContext.putVariable("receivable", receivable); } - // TODO @liuhongfeng:缺一个取消合同的接口;只有草稿、审批中可以取消;CrmAuditStatusEnum + @Override + public void updateReceivableAuditStatus(BpmResultListenerRespDTO event) { + convertAuditStatus(event); + // 更新回款审批状态 + receivableMapper.updateById(new CrmReceivableDO().setId(Long.parseLong(event.getBusinessKey())) + .setAuditStatus(event.getResult())); + } - // TODO @liuhongfeng:缺一个发起审批的接口;只有草稿可以发起审批;CrmAuditStatusEnum + // TODO @liuhongfeng:缺一个取消回款的接口;只有草稿、审批中可以取消;CrmAuditStatusEnum @Override + @Transactional(rollbackFor = Exception.class) @LogRecord(type = CRM_RECEIVABLE_TYPE, subType = CRM_RECEIVABLE_DELETE_SUB_TYPE, bizNo = "{{#id}}", success = CRM_RECEIVABLE_DELETE_SUCCESS) @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) public void deleteReceivable(Long id) { - // TODO @liuhongfeng:如果被 CrmReceivablePlanDO 所使用,则不允许删除 // 校验存在 CrmReceivableDO receivable = validateReceivableExists(id); + // 如果被 CrmReceivablePlanDO 所使用,则不允许删除 + if (Objects.nonNull(receivable.getPlanId()) && receivablePlanService.getReceivablePlan(receivable.getPlanId()) != null) { + throw exception(RECEIVABLE_DELETE_FAIL); + } // 删除 receivableMapper.deleteById(id); // 删除数据权限 - permissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), id); + permissionService.deletePermission(CrmBizTypeEnum.CRM_RECEIVABLE.getType(), id); // 记录操作日志上下文 LogRecordContext.putVariable("receivable", receivable); } + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_RECEIVABLE_TYPE, subType = CRM_RECEIVABLE_SUBMIT_SUB_TYPE, bizNo = "{{#id}}", + success = CRM_RECEIVABLE_SUBMIT_SUCCESS) + public void submitReceivable(Long id, Long userId) { + // 1. 校验回款是否在审批 + CrmReceivableDO receivable = validateReceivableExists(id); + if (ObjUtil.notEqual(receivable.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus())) { + throw exception(RECEIVABLE_SUBMIT_FAIL_NOT_DRAFT); + } + + // 2. 创建回款审批流程实例 + String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO() + .setProcessDefinitionKey(RECEIVABLE_APPROVE).setBusinessKey(String.valueOf(id))); + + // 3. 更新回款工作流编号 + receivableMapper.updateById(new CrmReceivableDO().setId(id).setProcessInstanceId(processInstanceId) + .setAuditStatus(CrmAuditStatusEnum.PROCESS.getStatus())); + + // 4. 记录日志 + LogRecordContext.putVariable("receivableNo", receivable.getNo()); + } + private CrmReceivableDO validateReceivableExists(Long id) { CrmReceivableDO receivable = receivableMapper.selectById(id); if (receivable == null) { diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/listener/CrmReceivableResultListener.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/listener/CrmReceivableResultListener.java new file mode 100644 index 0000000000..099d228aff --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/listener/CrmReceivableResultListener.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.crm.service.receivable.listener; + +import cn.iocoder.yudao.module.bpm.api.listener.BpmResultListenerApi; +import cn.iocoder.yudao.module.bpm.api.listener.dto.BpmResultListenerRespDTO; +import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivableService; +import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivableServiceImpl; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Component; + +// TODO @芋艿:后续改成支持 RPC + +/** + * 回款审批的结果的监听器实现类 + * + * @author HUIHUI + */ +@Component +public class CrmReceivableResultListener implements BpmResultListenerApi { + + @Resource + private CrmReceivableService receivableService; + + @Override + public String getProcessDefinitionKey() { + return CrmReceivableServiceImpl.RECEIVABLE_APPROVE; + } + + @Override + public void onEvent(BpmResultListenerRespDTO event) { + receivableService.updateReceivableAuditStatus(event); + } + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmAuditStatusUtils.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmAuditStatusUtils.java new file mode 100644 index 0000000000..017045e6e1 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmAuditStatusUtils.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.crm.util; + +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.module.bpm.api.listener.dto.BpmResultListenerRespDTO; +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; + +/** + * CRM 流程工具类 + * + * @author HUIHUI + */ +public class CrmAuditStatusUtils { + + public static void convertAuditStatus(BpmResultListenerRespDTO event) { + // 判断下状态是否符合预期 + if (!isEndResult(event.getResult())) { + return; + } + // 状态转换 + if (ObjUtil.equal(event.getResult(), BpmProcessInstanceResultEnum.APPROVE.getResult())) { + event.setResult(CrmAuditStatusEnum.APPROVE.getStatus()); + } + if (ObjUtil.equal(event.getResult(), BpmProcessInstanceResultEnum.REJECT.getResult())) { + event.setResult(CrmAuditStatusEnum.REJECT.getStatus()); + } + if (ObjUtil.equal(event.getResult(), BpmProcessInstanceResultEnum.CANCEL.getResult())) { + event.setResult(CrmAuditStatusEnum.CANCEL.getStatus()); + } + } + + /** + * 判断该结果是否处于 End 最终结果 + * + * @param result 结果 + * @return 是否 + */ + public static boolean isEndResult(Integer result) { + return ObjectUtils.equalsAny(result, BpmProcessInstanceResultEnum.APPROVE.getResult(), + BpmProcessInstanceResultEnum.REJECT.getResult(), BpmProcessInstanceResultEnum.CANCEL.getResult()); + } + +}