diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java index 01d2e80eb..711797cd2 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java @@ -122,7 +122,12 @@ public class LocalDateTimeUtils { return date.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX); } - // TODO @puhui999:加下注释哈; + /** + * 获取指定日期到现在过了几天,如果指定日期在当前日期之后,获取结果为负。 + * + * @param dateTime 日期 + * @return 相差天数 + */ public static Long between(LocalDateTime dateTime) { return LocalDateTimeUtil.between(dateTime, LocalDateTime.now(), ChronoUnit.DAYS); } diff --git a/yudao-module-crm/yudao-module-crm-api/pom.xml b/yudao-module-crm/yudao-module-crm-api/pom.xml index 94e129626..86d28a6aa 100644 --- a/yudao-module-crm/yudao-module-crm-api/pom.xml +++ b/yudao-module-crm/yudao-module-crm-api/pom.xml @@ -28,6 +28,12 @@ spring-boot-starter-validation true + + cn.iocoder.boot + yudao-module-system-api + ${revision} + true + 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 4c368b18e..84df67c13 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 @@ -44,6 +44,7 @@ public interface ErrorCodeConstants { ErrorCode CUSTOMER_UNLOCK_FAIL_IS_UNLOCK = new ErrorCode(1_020_006_008, "解锁客户失败,它已经处于未锁定状态"); ErrorCode CUSTOMER_LOCK_EXCEED_LIMIT = new ErrorCode(1_020_006_009, "锁定客户失败,超出锁定规则上限"); ErrorCode CUSTOMER_OWNER_EXCEED_LIMIT = new ErrorCode(1_020_006_010, "操作失败,超出客户数拥有上限"); + ErrorCode CUSTOMER_DELETE_FAIL_HAVE_REFERENCE = new ErrorCode(1_020_006_011, "删除客户失败,有关联{}"); // ========== 权限管理 1_020_007_000 ========== ErrorCode CRM_PERMISSION_NOT_EXISTS = new ErrorCode(1_020_007_000, "数据权限不存在"); @@ -54,6 +55,7 @@ public interface ErrorCodeConstants { 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_SELF_PERMISSION_FAIL_EXIST_OWNER = new ErrorCode(1_020_007_007, "删除数据权限失败,原因:不能删除负责人"); + ErrorCode CRM_PERMISSION_CREATE_FAIL = new ErrorCode(1_020_007_008, "创建数据权限失败,原因:所加用户已有权限"); // ========== 产品 1_020_008_000 ========== ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_020_008_000, "产品不存在"); @@ -77,4 +79,7 @@ public interface ErrorCodeConstants { // ========== 客户公海规则设置 1_020_012_000 ========== ErrorCode CUSTOMER_LIMIT_CONFIG_NOT_EXISTS = new ErrorCode(1_020_012_000, "客户限制配置不存在"); + // ========== 跟进记录 1_020_013_000 ========== + ErrorCode FOLLOW_UP_RECORD_NOT_EXISTS = new ErrorCode(1_020_013_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 057932ad8..40e835d9b 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 @@ -1,5 +1,8 @@ package cn.iocoder.yudao.module.crm.enums; +import static cn.iocoder.yudao.module.crm.enums.operatelog.CrmParseFunctionNameConstants.GET_CONTRACT_BY_ID; +import static cn.iocoder.yudao.module.system.enums.operatelog.SysParseFunctionNameConstants.GET_ADMIN_USER_BY_ID; + /** * CRM 操作日志枚举 * 目的:统一管理,也减少 Service 里各种“复杂”字符串 @@ -22,9 +25,9 @@ public interface LogRecordConstants { String CRM_CUSTOMER_DELETE_SUB_TYPE = "删除客户"; String CRM_CUSTOMER_DELETE_SUCCESS = "删除了客户【{{#customerName}}】"; String CRM_CUSTOMER_TRANSFER_SUB_TYPE = "转移客户"; - String CRM_CUSTOMER_TRANSFER_SUCCESS = "将客户【{{#crmCustomer.name}}】的负责人从【{getAdminUserById{#crmCustomer.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; - String CRM_CUSTOMER_LOCK_SUB_TYPE = "{{#crmCustomer.lockStatus ? '解锁客户' : '锁定客户'}}"; - String CRM_CUSTOMER_LOCK_SUCCESS = "{{#crmCustomer.lockStatus ? '将客户【' + #crmCustomer.name + '】解锁' : '将客户【' + #crmCustomer.name + '】锁定'}}"; + String CRM_CUSTOMER_TRANSFER_SUCCESS = "将客户【{{#customer.name}}】的负责人从【{" + GET_ADMIN_USER_BY_ID + "{#customer.ownerUserId}}】变更为了【{" + GET_ADMIN_USER_BY_ID + "{#reqVO.newOwnerUserId}}】"; + String CRM_CUSTOMER_LOCK_SUB_TYPE = "{{#customer.lockStatus ? '解锁客户' : '锁定客户'}}"; + String CRM_CUSTOMER_LOCK_SUCCESS = "{{#customer.lockStatus ? '将客户【' + #customer.name + '】解锁' : '将客户【' + #customer.name + '】锁定'}}"; String CRM_CUSTOMER_POOL_SUB_TYPE = "客户放入公海"; String CRM_CUSTOMER_POOL_SUCCESS = "将客户【{{#customerName}}】放入了公海"; String CRM_CUSTOMER_RECEIVE_SUB_TYPE = "{{#ownerUserName != null ? '分配客户' : '领取客户'}}"; @@ -49,14 +52,38 @@ public interface LogRecordConstants { // ======================= CRM_CONTACT 联系人 ======================= String CRM_CONTACT_TYPE = "CRM 联系人"; + String CRM_CONTACT_CREATE_SUB_TYPE = "创建联系人"; + String CRM_CONTACT_CREATE_SUCCESS = "创建了联系人{{#contact.name}}"; + String CRM_CONTACT_UPDATE_SUB_TYPE = "更新联系人"; + String CRM_CONTACT_UPDATE_SUCCESS = "更新了联系人【{{#contactName}}】: {_DIFF{#updateReqVO}}"; + String CRM_CONTACT_DELETE_SUB_TYPE = "删除联系人"; + String CRM_CONTACT_DELETE_SUCCESS = "删除了联系人【{{#contactName}}】"; + String CRM_CONTACT_TRANSFER_SUB_TYPE = "转移联系人"; + String CRM_CONTACT_TRANSFER_SUCCESS = "将联系人【{{#contact.name}}】的负责人从【{" + GET_ADMIN_USER_BY_ID + "{#contact.ownerUserId}}】变更为了【{" + GET_ADMIN_USER_BY_ID + "{#reqVO.newOwnerUserId}}】"; // ======================= CRM_BUSINESS 商机 ======================= String CRM_BUSINESS_TYPE = "CRM 商机"; + String CRM_BUSINESS_CREATE_SUB_TYPE = "创建商机"; + String CRM_BUSINESS_CREATE_SUCCESS = "创建了商机{{#business.name}}"; + String CRM_BUSINESS_UPDATE_SUB_TYPE = "更新商机"; + String CRM_BUSINESS_UPDATE_SUCCESS = "更新了商机【{{#businessName}}】: {_DIFF{#updateReqVO}}"; + String CRM_BUSINESS_DELETE_SUB_TYPE = "删除商机"; + String CRM_BUSINESS_DELETE_SUCCESS = "删除了商机【{{#businessName}}】"; + String CRM_BUSINESS_TRANSFER_SUB_TYPE = "转移商机"; + String CRM_BUSINESS_TRANSFER_SUCCESS = "将商机【{{#business.name}}】的负责人从【{" + GET_ADMIN_USER_BY_ID + "{#business.ownerUserId}}】变更为了【{" + GET_ADMIN_USER_BY_ID + "{#reqVO.newOwnerUserId}}】"; // ======================= CRM_CONTRACT 合同 ======================= String CRM_CONTRACT_TYPE = "CRM 合同"; + String CRM_CONTRACT_CREATE_SUB_TYPE = "创建合同"; + String CRM_CONTRACT_CREATE_SUCCESS = "创建了合同{{#contract.name}}"; + String CRM_CONTRACT_UPDATE_SUB_TYPE = "更新合同"; + String CRM_CONTRACT_UPDATE_SUCCESS = "更新了合同【{{#contractName}}】: {_DIFF{#updateReqVO}}"; + String CRM_CONTRACT_DELETE_SUB_TYPE = "删除合同"; + String CRM_CONTRACT_DELETE_SUCCESS = "删除了合同【{{#contractName}}】"; + String CRM_CONTRACT_TRANSFER_SUB_TYPE = "转移合同"; + String CRM_CONTRACT_TRANSFER_SUCCESS = "将合同【{{#contract.name}}】的负责人从【{" + GET_ADMIN_USER_BY_ID + "{#contract.ownerUserId}}】变更为了【{" + GET_ADMIN_USER_BY_ID + "{#reqVO.newOwnerUserId}}】"; // ======================= CRM_PRODUCT 产品 ======================= @@ -79,9 +106,21 @@ public interface LogRecordConstants { // ======================= CRM_RECEIVABLE 回款 ======================= String CRM_RECEIVABLE_TYPE = "CRM 回款"; + String CRM_RECEIVABLE_CREATE_SUB_TYPE = "创建回款"; + String CRM_RECEIVABLE_CREATE_SUCCESS = "创建了合同【{" + GET_CONTRACT_BY_ID + "{#receivable.contractId}}】的第【{{#receivable.period}}】期回款"; + String CRM_RECEIVABLE_UPDATE_SUB_TYPE = "更新回款"; + String CRM_RECEIVABLE_UPDATE_SUCCESS = "更新了合同【{" + GET_CONTRACT_BY_ID + "{#receivable.contractId}}】的第【{{#receivable.period}}】期回款: {_DIFF{#updateReqVO}}"; + String CRM_RECEIVABLE_DELETE_SUB_TYPE = "删除回款"; + String CRM_RECEIVABLE_DELETE_SUCCESS = "删除了合同【{" + GET_CONTRACT_BY_ID + "{#receivable.contractId}}】的第【{{#receivable.period}}】期回款"; // ======================= CRM_RECEIVABLE_PLAN 回款计划 ======================= String CRM_RECEIVABLE_PLAN_TYPE = "CRM 回款计划"; + String CRM_RECEIVABLE_PLAN_CREATE_SUB_TYPE = "创建回款计划"; + String CRM_RECEIVABLE_PLAN_CREATE_SUCCESS = "创建了合同【{" + GET_CONTRACT_BY_ID + "{#receivablePlan.contractId}}】的第【{{#receivablePlan.period}}】期回款计划"; + String CRM_RECEIVABLE_PLAN_UPDATE_SUB_TYPE = "更新回款计划"; + String CRM_RECEIVABLE_PLAN_UPDATE_SUCCESS = "更新了合同【{" + GET_CONTRACT_BY_ID + "{#receivablePlan.contractId}}】的第【{{#receivablePlan.period}}】期回款计划: {_DIFF{#updateReqVO}}"; + String CRM_RECEIVABLE_PLAN_DELETE_SUB_TYPE = "删除回款计划"; + String CRM_RECEIVABLE_PLAN_DELETE_SUCCESS = "删除了合同【{" + GET_CONTRACT_BY_ID + "{#receivablePlan.contractId}}】的第【{{#receivablePlan.period}}】期回款计划"; } diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/operatelog/CrmParseFunctionNameConstants.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/operatelog/CrmParseFunctionNameConstants.java new file mode 100644 index 000000000..7aa8e05fd --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/operatelog/CrmParseFunctionNameConstants.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.crm.enums.operatelog; + +/** + * functionName 常量枚举 + * 方便别的模块调用 + * + * @author HUIHUI + */ +public interface CrmParseFunctionNameConstants { + + String GET_CONTACT_BY_ID = "getContactById"; // 获取联系人信息 + String GET_CUSTOMER_BY_ID = "getCustomerById"; // 获取客户信息 + String GET_CUSTOMER_INDUSTRY = "getCustomerIndustry"; // 获取客户行业信息 + String GET_CUSTOMER_LEVEL = "getCustomerLevel"; // 获取客户级别 + String GET_CUSTOMER_SOURCE = "getCustomerSource"; // 获取客户来源 + String GET_CONTRACT_BY_ID = "getContractById"; // 获取合同信息 + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactSaveReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactSaveReqVO.java index 4f5287f44..5f9c23d1d 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactSaveReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactSaveReqVO.java @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; import cn.iocoder.yudao.framework.common.validation.Mobile; import cn.iocoder.yudao.framework.common.validation.Telephone; -import cn.iocoder.yudao.module.crm.framework.operatelog.core.*; import com.mzt.logapi.starter.annotation.DiffLogField; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.Email; @@ -14,10 +13,13 @@ import java.time.LocalDateTime; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +import static cn.iocoder.yudao.module.crm.enums.operatelog.CrmParseFunctionNameConstants.GET_CONTACT_BY_ID; +import static cn.iocoder.yudao.module.crm.enums.operatelog.CrmParseFunctionNameConstants.GET_CUSTOMER_BY_ID; +import static cn.iocoder.yudao.module.system.enums.operatelog.SysParseFunctionNameConstants.*; @Schema(description = "管理后台 - CRM 联系人创建/更新 Request VO") @Data -public class CrmContactSaveReqVO { +public class CrmContactSaveReqVO { @Schema(description = "主键", example = "3167") private Long id; @@ -28,11 +30,11 @@ public class CrmContactSaveReqVO { private String name; @Schema(description = "客户编号", example = "10795") - @DiffLogField(name = "姓名", function = CrmCustomerParseFunction.NAME) + @DiffLogField(name = "姓名", function = GET_CUSTOMER_BY_ID) private Long customerId; @Schema(description = "性别") - @DiffLogField(name = "性别", function = CrmSexParseFunction.NAME) + @DiffLogField(name = "性别", function = GET_SEX) private Integer sex; @Schema(description = "职位") @@ -40,11 +42,11 @@ public class CrmContactSaveReqVO { private String post; @Schema(description = "是否关键决策人") - @DiffLogField(name = "关键决策人", function = CrmBooleanParseFunction.NAME) + @DiffLogField(name = "关键决策人", function = GET_BOOLEAN) private Boolean master; @Schema(description = "直属上级", example = "23457") - @DiffLogField(name = "直属上级", function = CrmContactParseFunction.NAME) + @DiffLogField(name = "直属上级", function = GET_CONTACT_BY_ID) private Long parentId; @Schema(description = "手机号", example = "1387171766") @@ -71,7 +73,7 @@ public class CrmContactSaveReqVO { private String email; @Schema(description = "地区编号", example = "20158") - @DiffLogField(name = "所在地", function = "getAreaById") + @DiffLogField(name = "所在地", function = GET_AREA) private Integer areaId; @Schema(description = "地址") @@ -84,7 +86,7 @@ public class CrmContactSaveReqVO { @Schema(description = "负责人用户编号", example = "14334") @NotNull(message = "负责人不能为空") - @DiffLogField(name = "负责人", function = CrmSysUserParseFunction.NAME) + @DiffLogField(name = "负责人", function = GET_ADMIN_USER_BY_ID) 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/customer/CrmCustomerController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java index 60903bd0a..33b04b8aa 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.crm.controller.admin.customer; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; @@ -32,6 +34,7 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.io.IOException; +import java.time.LocalDateTime; import java.util.List; import java.util.Map; import java.util.stream.Stream; @@ -112,32 +115,40 @@ public class CrmCustomerController { } // 2. 拼接数据 - Map poolDayMap = getPoolDayMap(pageResult); // 距离进入公海的时间 + Map poolDayMap = null; + if (ObjUtil.notEqual(pageVO.getPool(), Boolean.TRUE)) { + poolDayMap = getPoolDayMap(pageResult.getList()); // 距离进入公海的时间 + } Map userMap = adminUserApi.getUserMap( convertSetByFlatMap(pageResult.getList(), user -> Stream.of(Long.parseLong(user.getCreator()), user.getOwnerUserId()))); Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); return success(CrmCustomerConvert.INSTANCE.convertPage(pageResult, userMap, deptMap, poolDayMap)); } - // TODO @puhui999:加下注释哈; - private Map getPoolDayMap(PageResult pageResult) { - Map poolDayMap = null; + /** + * 获取距离进入公海的时间 + * + * @param customerList 客户列表 + * @return Map + */ + private Map getPoolDayMap(List customerList) { CrmCustomerPoolConfigDO customerPoolConfig = customerPoolConfigService.getCustomerPoolConfig(); - // TODO @puhui999:if return 减少括号 - if (customerPoolConfig != null && customerPoolConfig.getEnabled()) { // 有公海配置的情况 - // TODO @puhui999:item 改成 customer 更好,容易理解; - poolDayMap = convertMap(pageResult.getList(), CrmCustomerDO::getId, item -> { - long dealExpireDay = 0; - if (!item.getDealStatus()) { // 检查是否成交 - dealExpireDay = customerPoolConfig.getDealExpireDays() - LocalDateTimeUtils.between(item.getCreateTime()); - } - // TODO @puhui999:需要考虑 contactLastTime 为空的情况哈; - long contactExpireDay = customerPoolConfig.getContactExpireDays() - LocalDateTimeUtils.between(item.getContactLastTime()); - return dealExpireDay == 0 ? contactExpireDay : Math.min(dealExpireDay, contactExpireDay); - }); - // TODO @puhui999:需要考虑 lock 的情况么? + if (customerPoolConfig == null || !customerPoolConfig.getEnabled()) { + return MapUtil.empty(); } - return poolDayMap; + // TODO @puhui999:需要考虑 lock 的情况么? 回复:锁定正常显示距离进入公海的时间有个提示 + return convertMap(customerList, CrmCustomerDO::getId, customer -> { + long dealExpireDay = 0; + if (!customer.getDealStatus()) { // 检查是否成交 + dealExpireDay = customerPoolConfig.getDealExpireDays() - LocalDateTimeUtils.between(customer.getCreateTime()); + } + LocalDateTime lastTime = customer.getContactLastTime() != null ? customer.getContactLastTime() : customer.getCreateTime(); + long contactExpireDay = customerPoolConfig.getContactExpireDays() - LocalDateTimeUtils.between(lastTime); + if (contactExpireDay < 0) { + contactExpireDay = 0; // 如果为负的话重置为零 + } + return Math.min(dealExpireDay, contactExpireDay); + }); } @GetMapping(value = "/list-all-simple") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerPoolConfigController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerPoolConfigController.java index 5fc61fc8b..94e5347fd 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerPoolConfigController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerPoolConfigController.java @@ -1,9 +1,9 @@ package cn.iocoder.yudao.module.crm.controller.admin.customer; import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.poolconfig.CrmCustomerPoolConfigRespVO; import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.poolconfig.CrmCustomerPoolConfigSaveReqVO; -import cn.iocoder.yudao.module.crm.convert.customer.CrmCustomerConvert; import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerPoolConfigService; import io.swagger.v3.oas.annotations.Operation; @@ -30,7 +30,7 @@ public class CrmCustomerPoolConfigController { @PreAuthorize("@ss.hasPermission('crm:customer-pool-config:query')") public CommonResult getCustomerPoolConfig() { CrmCustomerPoolConfigDO customerPoolConfig = customerPoolConfigService.getCustomerPoolConfig(); - return success(CrmCustomerConvert.INSTANCE.convert(customerPoolConfig)); + return success(BeanUtils.toBean(customerPoolConfig, CrmCustomerPoolConfigRespVO.class)); } @PutMapping("/save") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerDistributeReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerDistributeReqVO.java index fcb9ac57f..24113ed12 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerDistributeReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerDistributeReqVO.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.customer.vo; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Data; @@ -11,7 +12,7 @@ import java.util.List; public class CrmCustomerDistributeReqVO { @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1024]") - @NotNull(message = "客户编号不能为空") // TODO @puhui999:list 是 @NotEmpty + @NotEmpty(message = "客户编号不能为空") private List ids; @Schema(description = "负责人", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerSaveReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerSaveReqVO.java index 05b01c101..992bbaddc 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerSaveReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerSaveReqVO.java @@ -5,9 +5,6 @@ import cn.iocoder.yudao.framework.common.validation.Mobile; import cn.iocoder.yudao.framework.common.validation.Telephone; import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; import cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLevelEnum; -import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmIndustryParseFunction; -import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmLevelParseFunction; -import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmSourceParseFunction; import com.mzt.logapi.starter.annotation.DiffLogField; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.Email; @@ -20,6 +17,8 @@ import java.time.LocalDateTime; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_INDUSTRY; +import static cn.iocoder.yudao.module.crm.enums.operatelog.CrmParseFunctionNameConstants.*; +import static cn.iocoder.yudao.module.system.enums.operatelog.SysParseFunctionNameConstants.GET_AREA; @Schema(description = "管理后台 - CRM 客户新增/修改 Request VO") @Data @@ -34,17 +33,17 @@ public class CrmCustomerSaveReqVO { private String name; @Schema(description = "所属行业", example = "1") - @DiffLogField(name = "所属行业", function = CrmIndustryParseFunction.NAME) + @DiffLogField(name = "所属行业", function = GET_CUSTOMER_INDUSTRY) @DictFormat(CRM_CUSTOMER_INDUSTRY) private Integer industryId; @Schema(description = "客户等级", example = "2") - @DiffLogField(name = "客户等级", function = CrmLevelParseFunction.NAME) + @DiffLogField(name = "客户等级", function = GET_CUSTOMER_LEVEL) @InEnum(CrmCustomerLevelEnum.class) private Integer level; @Schema(description = "客户来源", example = "3") - @DiffLogField(name = "客户来源", function = CrmSourceParseFunction.NAME) + @DiffLogField(name = "客户来源", function = GET_CUSTOMER_SOURCE) private Integer source; @Schema(description = "手机", example = "18000000000") @@ -87,7 +86,7 @@ public class CrmCustomerSaveReqVO { private String remark; @Schema(description = "地区编号", example = "20158") - @DiffLogField(name = "地区编号", function = "getAreaById") + @DiffLogField(name = "地区编号", function = GET_AREA) private Integer areaId; @Schema(description = "详细地址", example = "北京市海淀区") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/limitconfig/CrmCustomerLimitConfigSaveReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/limitconfig/CrmCustomerLimitConfigSaveReqVO.java index 69ab5e628..e7baa3132 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/limitconfig/CrmCustomerLimitConfigSaveReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/limitconfig/CrmCustomerLimitConfigSaveReqVO.java @@ -7,6 +7,9 @@ import lombok.Data; import java.util.List; +import static cn.iocoder.yudao.module.system.enums.operatelog.SysParseFunctionNameConstants.GET_ADMIN_USER_BY_ID; +import static cn.iocoder.yudao.module.system.enums.operatelog.SysParseFunctionNameConstants.GET_DEPT_BY_ID; + @Schema(description = "管理后台 - 客户限制配置创建/更新 Request VO") @Data public class CrmCustomerLimitConfigSaveReqVO { @@ -19,13 +22,12 @@ public class CrmCustomerLimitConfigSaveReqVO { @DiffLogField(name = "规则类型") private Integer type; - // TODO @puhui999:可以把 Function 那的 functionName 搞成 NAME 枚举,这里直接引用。这样后续改动更方便哈。 @Schema(description = "规则适用人群") - @DiffLogField(name = "规则适用人群", function = "getAdminUserById") + @DiffLogField(name = "规则适用人群", function = GET_ADMIN_USER_BY_ID) private List userIds; @Schema(description = "规则适用部门") - @DiffLogField(name = "规则适用部门", function = "getDeptById") + @DiffLogField(name = "规则适用部门", function = GET_DEPT_BY_ID) private List deptIds; @Schema(description = "数量上限", requiredMode = Schema.RequiredMode.REQUIRED, example = "28384") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/CrmFollowUpRecordController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/CrmFollowUpRecordController.java new file mode 100644 index 000000000..93c02542a --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/CrmFollowUpRecordController.java @@ -0,0 +1,94 @@ +package cn.iocoder.yudao.module.crm.controller.admin.followup; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +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.followup.vo.CrmFollowUpRecordPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.followup.CrmFollowUpRecordDO; +import cn.iocoder.yudao.module.crm.service.followup.CrmFollowUpRecordService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; + + +@Tag(name = "管理后台 - 跟进记录") +@RestController +@RequestMapping("/crm/follow-up-record") +@Validated +public class CrmFollowUpRecordController { + + @Resource + private CrmFollowUpRecordService crmFollowUpRecordService; + + @PostMapping("/create") + @Operation(summary = "创建跟进记录") + @PreAuthorize("@ss.hasPermission('crm:follow-up-record:create')") + public CommonResult createFollowUpRecord(@Valid @RequestBody CrmFollowUpRecordSaveReqVO createReqVO) { + return success(crmFollowUpRecordService.createFollowUpRecord(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新跟进记录") + @PreAuthorize("@ss.hasPermission('crm:follow-up-record:update')") + public CommonResult updateFollowUpRecord(@Valid @RequestBody CrmFollowUpRecordSaveReqVO updateReqVO) { + crmFollowUpRecordService.updateFollowUpRecord(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除跟进记录") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('crm:follow-up-record:delete')") + public CommonResult deleteFollowUpRecord(@RequestParam("id") Long id) { + crmFollowUpRecordService.deleteFollowUpRecord(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得跟进记录") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('crm:follow-up-record:query')") + public CommonResult getFollowUpRecord(@RequestParam("id") Long id) { + CrmFollowUpRecordDO followUpRecord = crmFollowUpRecordService.getFollowUpRecord(id); + return success(BeanUtils.toBean(followUpRecord, CrmFollowUpRecordRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得跟进记录分页") + @PreAuthorize("@ss.hasPermission('crm:follow-up-record:query')") + public CommonResult> getFollowUpRecordPage(@Valid CrmFollowUpRecordPageReqVO pageReqVO) { + PageResult pageResult = crmFollowUpRecordService.getFollowUpRecordPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, CrmFollowUpRecordRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出跟进记录 Excel") + @PreAuthorize("@ss.hasPermission('crm:follow-up-record:export')") + @OperateLog(type = EXPORT) + public void exportFollowUpRecordExcel(@Valid CrmFollowUpRecordPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = crmFollowUpRecordService.getFollowUpRecordPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "跟进记录.xls", "数据", CrmFollowUpRecordRespVO.class, + BeanUtils.toBean(list, CrmFollowUpRecordRespVO.class)); + } + +} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordPageReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordPageReqVO.java new file mode 100644 index 000000000..04d63b85e --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordPageReqVO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.crm.controller.admin.followup.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +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; + +@Schema(description = "管理后台 - 跟进记录分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CrmFollowUpRecordPageReqVO extends PageParam { + + @Schema(description = "数据类型", example = "2") + private Integer bizType; + + @Schema(description = "数据编号", example = "5564") + private Long bizId; + + @Schema(description = "跟进类型", example = "2") + private Integer type; + + @Schema(description = "下次联系时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] nextTime; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordRespVO.java new file mode 100644 index 000000000..c8f0a0453 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordRespVO.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.crm.controller.admin.followup.vo; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 跟进记录 Response VO") +@Data +@ExcelIgnoreUnannotated +public class CrmFollowUpRecordRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28800") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "数据类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("数据类型") + private Integer bizType; + + @Schema(description = "数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "5564") + @ExcelProperty("数据编号") + private Long bizId; + + @Schema(description = "跟进类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty(value = "跟进类型", converter = DictConvert.class) + @DictFormat("crm_follow_up_type") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Integer type; + + @Schema(description = "跟进内容", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("跟进内容") + private String content; + + @Schema(description = "下次联系时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("下次联系时间") + private LocalDateTime nextTime; + + @Schema(description = "关联的商机编号数组") + @ExcelProperty("关联的商机编号数组") + private String businessIds; + + @Schema(description = "关联的联系人编号数组") + @ExcelProperty("关联的联系人编号数组") + private String contactIds; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordSaveReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordSaveReqVO.java new file mode 100644 index 000000000..b78844278 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordSaveReqVO.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.crm.controller.admin.followup.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 跟进记录新增/修改 Request VO") +@Data +public class CrmFollowUpRecordSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28800") + private Long id; + + @Schema(description = "数据类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "数据类型不能为空") + private Integer bizType; + + @Schema(description = "数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "5564") + @NotNull(message = "数据编号不能为空") + private Long bizId; + + @Schema(description = "跟进类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "跟进类型不能为空") + private Integer type; + + @Schema(description = "跟进内容", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "跟进内容不能为空") + private String content; + + @Schema(description = "下次联系时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "下次联系时间不能为空") + private LocalDateTime nextTime; + + @Schema(description = "关联的商机编号数组") + private String businessIds; + + @Schema(description = "关联的联系人编号数组") + private String contactIds; + +} \ No newline at end of file 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 e5ae4fd9b..8516ebd66 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 @@ -7,7 +7,10 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; 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.*; +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.convert.receivable.CrmReceivableConvert; import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; @@ -59,7 +62,7 @@ public class CrmReceivableController { @Operation(summary = "创建回款") @PreAuthorize("@ss.hasPermission('crm:receivable:create')") public CommonResult createReceivable(@Valid @RequestBody CrmReceivableCreateReqVO createReqVO) { - return success(receivableService.createReceivable(createReqVO)); + return success(receivableService.createReceivable(createReqVO, getLoginUserId())); } @PutMapping("/update") @@ -141,12 +144,4 @@ public class CrmReceivableController { return CrmReceivableConvert.INSTANCE.convertPage(pageResult, userMap, customerList, contractList); } - @PutMapping("/transfer") - @Operation(summary = "回款转移") - @PreAuthorize("@ss.hasPermission('crm:receivable:update')") - public CommonResult transfer(@Valid @RequestBody CrmReceivableTransferReqVO reqVO) { - receivableService.transferReceivable(reqVO, 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/CrmReceivablePlanController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java index 7ff0a9385..481914e8b 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java @@ -7,7 +7,10 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; 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.plan.*; +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanCreateReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanUpdateReqVO; import cn.iocoder.yudao.module.crm.convert.receivable.CrmReceivablePlanConvert; import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; @@ -148,12 +151,4 @@ public class CrmReceivablePlanController { return CrmReceivablePlanConvert.INSTANCE.convertPage(pageResult, userMap, customerList, contractList, receivableList); } - @PutMapping("/transfer") - @Operation(summary = "回款计划转移") - @PreAuthorize("@ss.hasPermission('crm:receivable-plan:update')") - public CommonResult transfer(@Valid @RequestBody CrmReceivablePlanTransferReqVO reqVO) { - receivablePlanService.transferReceivablePlan(reqVO, getLoginUserId()); - return success(true); - } - } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/customer/CrmCustomerConvert.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/customer/CrmCustomerConvert.java index efc9977fe..939ec452a 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/customer/CrmCustomerConvert.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/customer/CrmCustomerConvert.java @@ -3,13 +3,8 @@ package cn.iocoder.yudao.module.crm.convert.customer; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerSaveReqVO; import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerTransferReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.poolconfig.CrmCustomerPoolConfigRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.poolconfig.CrmCustomerPoolConfigSaveReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; @@ -31,9 +26,6 @@ public interface CrmCustomerConvert { CrmCustomerConvert INSTANCE = Mappers.getMapper(CrmCustomerConvert.class); - // TODO @puhui999:可以清理掉可以用 BeanUtil 替代的方法哈 - CrmCustomerDO convert(CrmCustomerSaveReqVO bean); - CrmCustomerRespVO convert(CrmCustomerDO bean); /** @@ -74,12 +66,4 @@ public interface CrmCustomerConvert { return result; } - CrmCustomerPoolConfigRespVO convert(CrmCustomerPoolConfigDO customerPoolConfig); - - CrmCustomerPoolConfigDO convert(CrmCustomerPoolConfigSaveReqVO updateReqVO); - - // TODO @min:使用 BeanUtils 拷贝哈。我们慢慢简单的对象,不再直接基于 convert 做啦。 - @Mapping(ignore = true, target = "id") - CrmCustomerSaveReqVO convert(CrmClueDO bean); - } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/customer/CrmCustomerLimitConfigConvert.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/customer/CrmCustomerLimitConfigConvert.java index 913865bdb..3566363af 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/customer/CrmCustomerLimitConfigConvert.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/customer/CrmCustomerLimitConfigConvert.java @@ -3,14 +3,12 @@ package cn.iocoder.yudao.module.crm.convert.customer; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigSaveReqVO; import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerLimitConfigDO; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; -import java.util.List; import java.util.Map; /** @@ -23,13 +21,8 @@ public interface CrmCustomerLimitConfigConvert { CrmCustomerLimitConfigConvert INSTANCE = Mappers.getMapper(CrmCustomerLimitConfigConvert.class); - // TODO @puhui999:可以把 convert 改成 BeanUtils - CrmCustomerLimitConfigDO convert(CrmCustomerLimitConfigSaveReqVO bean); - CrmCustomerLimitConfigRespVO convert(CrmCustomerLimitConfigDO bean); - List convertList(List list); - PageResult convertPage(PageResult page); default PageResult convertPage(PageResult pageResult, diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/CrmContactDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/CrmContactDO.java index 74ced6032..c2dec247d 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/CrmContactDO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/CrmContactDO.java @@ -105,7 +105,10 @@ public class CrmContactDO extends BaseDO { * 最后跟进时间 */ private LocalDateTime contactLastTime; - // TODO @puhui999:增加一个字段 contactLastContent;最后跟进内容 + /** + * 最后跟进内容 + */ + private String contactLastContent; /** * 下次联系时间 */ diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/customer/CrmCustomerDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/customer/CrmCustomerDO.java index c35778e3e..96e4bf520 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/customer/CrmCustomerDO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/customer/CrmCustomerDO.java @@ -118,7 +118,10 @@ public class CrmCustomerDO extends BaseDO { * 最后跟进时间 */ private LocalDateTime contactLastTime; - // TODO @puhui999:增加一个字段 contactLastContent;最后跟进内容 + /** + * 最后跟进内容 + */ + private String contactLastContent; /** * 下次联系时间 */ diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/followup/CrmFollowUpRecordDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/followup/CrmFollowUpRecordDO.java index b9138da92..600983205 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/followup/CrmFollowUpRecordDO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/followup/CrmFollowUpRecordDO.java @@ -1,10 +1,12 @@ package cn.iocoder.yudao.module.crm.dal.dataobject.followup; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; @@ -21,7 +23,7 @@ import java.util.List; * * @author 芋道源码 */ -@TableName(value = "crm_follow_up_record") +@TableName(value = "crm_follow_up_record", autoResultMap = true) @KeySequence("crm_follow_up_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @EqualsAndHashCode(callSuper = true) @@ -70,12 +72,14 @@ public class CrmFollowUpRecordDO extends BaseDO { * * 关联 {@link CrmBusinessDO#getId()} */ + @TableField(typeHandler = LongListTypeHandler.class) private List businessIds; /** * 关联的联系人编号数组 * * 关联 {@link CrmContactDO#getId()} */ + @TableField(typeHandler = LongListTypeHandler.class) private List contactIds; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java index 1d387149c..8b2fb76bd 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java @@ -28,6 +28,12 @@ public interface CrmContactMapper extends BaseMapperX { .set(CrmContactDO::getOwnerUserId, ownerUserId)); } + default int updateOwnerUserIdByCustomerId(Long customerId, Long ownerUserId) { + return update(new LambdaUpdateWrapper() + .eq(CrmContactDO::getCustomerId, customerId) + .set(CrmContactDO::getOwnerUserId, ownerUserId)); + } + default PageResult selectPageByCustomerId(CrmContactPageReqVO pageVO) { return selectPage(pageVO, new LambdaQueryWrapperX() .eq(CrmContactDO::getCustomerId, pageVO.getCustomerId()) // 指定客户编号 diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerPoolConfigMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerPoolConfigMapper.java index 1461ff6dd..06cf44e4f 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerPoolConfigMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerPoolConfigMapper.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.crm.dal.mysql.customer; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; import org.apache.ibatis.annotations.Mapper; @@ -11,4 +12,9 @@ import org.apache.ibatis.annotations.Mapper; */ @Mapper public interface CrmCustomerPoolConfigMapper extends BaseMapperX { + + default CrmCustomerPoolConfigDO selectOne() { + return selectOne(new LambdaQueryWrapperX().last("LIMIT 1")); + } + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/followup/CrmFollowUpRecordMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/followup/CrmFollowUpRecordMapper.java new file mode 100644 index 000000000..b45e5332c --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/followup/CrmFollowUpRecordMapper.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.followup; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordPageReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.followup.CrmFollowUpRecordDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 跟进记录 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface CrmFollowUpRecordMapper extends BaseMapperX { + + default PageResult selectPage(CrmFollowUpRecordPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(CrmFollowUpRecordDO::getBizType, reqVO.getBizType()) + .eqIfPresent(CrmFollowUpRecordDO::getBizId, reqVO.getBizId()) + .eqIfPresent(CrmFollowUpRecordDO::getType, reqVO.getType()) + .betweenIfPresent(CrmFollowUpRecordDO::getNextTime, reqVO.getNextTime()) + .betweenIfPresent(CrmFollowUpRecordDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(CrmFollowUpRecordDO::getId)); + } + +} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/permission/CrmPermissionMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/permission/CrmPermissionMapper.java index a797da779..71c0368ca 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/permission/CrmPermissionMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/permission/CrmPermissionMapper.java @@ -59,4 +59,11 @@ public interface CrmPermissionMapper extends BaseMapperX { .eq(CrmPermissionDO::getBizId, bizId)); } + default Long selectListByBiz(Collection bizTypes, Collection bizIds, Collection userIds) { + return selectCount(new LambdaQueryWrapperX() + .in(CrmPermissionDO::getBizType, bizTypes) + .in(CrmPermissionDO::getBizId, bizIds) + .in(CrmPermissionDO::getUserId, userIds)); + } + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmContactParseFunction.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmContactParseFunction.java index c6137d73a..928417dce 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmContactParseFunction.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmContactParseFunction.java @@ -8,8 +8,10 @@ import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import static cn.iocoder.yudao.module.crm.enums.operatelog.CrmParseFunctionNameConstants.GET_CONTACT_BY_ID; + /** - * 行业的 {@link IParseFunction} 实现类 + * CRM 联系人的 {@link IParseFunction} 实现类 * * @author HUIHUI */ @@ -17,8 +19,6 @@ import org.springframework.stereotype.Component; @Slf4j public class CrmContactParseFunction implements IParseFunction { - public static final String NAME = "getContactById"; - @Resource private CrmContactService contactService; @@ -29,7 +29,7 @@ public class CrmContactParseFunction implements IParseFunction { @Override public String functionName() { - return NAME; + return GET_CONTACT_BY_ID; } @Override diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmSysUserParseFunction.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmContractParseFunction.java similarity index 50% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmSysUserParseFunction.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmContractParseFunction.java index 22b1e90f3..051484e06 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmSysUserParseFunction.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmContractParseFunction.java @@ -1,26 +1,26 @@ package cn.iocoder.yudao.module.crm.framework.operatelog.core; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; +import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; import com.mzt.logapi.service.IParseFunction; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import static cn.iocoder.yudao.module.crm.enums.operatelog.CrmParseFunctionNameConstants.GET_CONTRACT_BY_ID; + /** - * 行业的 {@link IParseFunction} 实现类 + * CRM 合同的 {@link IParseFunction} 实现类 * * @author HUIHUI */ @Component @Slf4j -public class CrmSysUserParseFunction implements IParseFunction { - - public static final String NAME = "getUserById"; +public class CrmContractParseFunction implements IParseFunction { @Resource - private AdminUserApi adminUserApi; + private CrmContractService contractService; @Override public boolean executeBefore() { @@ -29,7 +29,7 @@ public class CrmSysUserParseFunction implements IParseFunction { @Override public String functionName() { - return NAME; + return GET_CONTRACT_BY_ID; } @Override @@ -37,8 +37,8 @@ public class CrmSysUserParseFunction implements IParseFunction { if (StrUtil.isEmptyIfStr(value)) { return ""; } - AdminUserRespDTO adminUserRespDTO = adminUserApi.getUser(Long.parseLong(value.toString())); - return adminUserRespDTO == null ? "" : adminUserRespDTO.getNickname(); + CrmContractDO contract = contractService.getContract(Long.parseLong(value.toString())); + return contract == null ? "" : contract.getName(); } } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmIndustryParseFunction.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerIndustryParseFunction.java similarity index 79% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmIndustryParseFunction.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerIndustryParseFunction.java index d750f1cfe..16721538d 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmIndustryParseFunction.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerIndustryParseFunction.java @@ -7,6 +7,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_INDUSTRY; +import static cn.iocoder.yudao.module.crm.enums.operatelog.CrmParseFunctionNameConstants.GET_CUSTOMER_INDUSTRY; /** * 行业的 {@link IParseFunction} 实现类 @@ -15,9 +16,7 @@ import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_I */ @Component @Slf4j -public class CrmIndustryParseFunction implements IParseFunction { - - public static final String NAME = "getIndustryById"; +public class CrmCustomerIndustryParseFunction implements IParseFunction { @Override public boolean executeBefore() { @@ -26,7 +25,7 @@ public class CrmIndustryParseFunction implements IParseFunction { @Override public String functionName() { - return NAME; + return GET_CUSTOMER_INDUSTRY; } @Override diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmLevelParseFunction.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerLevelParseFunction.java similarity index 80% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmLevelParseFunction.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerLevelParseFunction.java index f5b9e519e..291007d7d 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmLevelParseFunction.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerLevelParseFunction.java @@ -7,6 +7,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_LEVEL; +import static cn.iocoder.yudao.module.crm.enums.operatelog.CrmParseFunctionNameConstants.GET_CUSTOMER_LEVEL; /** * 客户等级的 {@link IParseFunction} 实现类 @@ -15,9 +16,7 @@ import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_L */ @Component @Slf4j -public class CrmLevelParseFunction implements IParseFunction { - - public static final String NAME = "getLevel"; +public class CrmCustomerLevelParseFunction implements IParseFunction { @Override public boolean executeBefore() { @@ -26,7 +25,7 @@ public class CrmLevelParseFunction implements IParseFunction { @Override public String functionName() { - return NAME; + return GET_CUSTOMER_LEVEL; } @Override diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerParseFunction.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerParseFunction.java index 7358813fc..6ec19e0f0 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerParseFunction.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerParseFunction.java @@ -8,8 +8,10 @@ import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import static cn.iocoder.yudao.module.crm.enums.operatelog.CrmParseFunctionNameConstants.GET_CUSTOMER_BY_ID; + /** - * 行业的 {@link IParseFunction} 实现类 + * CRM 客户的 {@link IParseFunction} 实现类 * * @author HUIHUI */ @@ -17,8 +19,6 @@ import org.springframework.stereotype.Component; @Slf4j public class CrmCustomerParseFunction implements IParseFunction { - public static final String NAME = "getCustomerById"; - @Resource private CrmCustomerService customerService; @@ -29,7 +29,7 @@ public class CrmCustomerParseFunction implements IParseFunction { @Override public String functionName() { - return NAME; + return GET_CUSTOMER_BY_ID; } @Override diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmSourceParseFunction.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerSourceParseFunction.java similarity index 71% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmSourceParseFunction.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerSourceParseFunction.java index 4d32b1114..1c5041915 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmSourceParseFunction.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerSourceParseFunction.java @@ -7,17 +7,18 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_SOURCE; +import static cn.iocoder.yudao.module.crm.enums.operatelog.CrmParseFunctionNameConstants.GET_CUSTOMER_SOURCE; /** - * 客户来源的 {@link IParseFunction} 实现类 + * CRM 客户来源的 {@link IParseFunction} 实现类 * * @author HUIHUI */ @Component @Slf4j -public class CrmSourceParseFunction implements IParseFunction { +public class CrmCustomerSourceParseFunction implements IParseFunction { - public static final String NAME = "getSource"; + public static final String NAME = "getCustomerSource"; @Override public boolean executeBefore() { @@ -26,7 +27,7 @@ public class CrmSourceParseFunction implements IParseFunction { @Override public String functionName() { - return NAME; + return GET_CUSTOMER_SOURCE; } @Override diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java index fad8930e4..c2b132648 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java @@ -98,4 +98,12 @@ public interface CrmBusinessService { */ void transferBusiness(CrmBusinessTransferReqVO reqVO, Long userId); + /** + * 获取关联客户的商机数量 + * + * @param customerId 客户编号 + * @return 数量 + */ + Long getBusinessCountByCustomerId(Long customerId); + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java index 58c2bccfe..03a14ceb6 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.crm.service.business; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil; 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.business.vo.business.CrmBusinessCreateReqVO; import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessPageReqVO; import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessTransferReqVO; @@ -17,6 +18,9 @@ import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPerm import cn.iocoder.yudao.module.crm.service.contact.CrmContactBusinessService; import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; +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; @@ -28,6 +32,7 @@ import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.BUSINESS_NOT_EXISTS; +import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; /** * 商机 Service 实现类 @@ -48,7 +53,8 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { @Override @Transactional(rollbackFor = Exception.class) - // TODO @商机待定:操作日志; + @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_CREATE_SUB_TYPE, bizNo = "{{#business.id}}", + success = CRM_BUSINESS_CREATE_SUCCESS) public Long createBusiness(CrmBusinessCreateReqVO createReqVO, Long userId) { // 1. 插入商机 CrmBusinessDO business = CrmBusinessConvert.INSTANCE.convert(createReqVO); @@ -60,17 +66,20 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { // 2. 创建数据权限 permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_BUSINESS.getType()) .setBizId(business.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人 + + // 4. 记录操作日志上下文 + LogRecordContext.putVariable("business", business); return business.getId(); } @Override @Transactional(rollbackFor = Exception.class) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#updateReqVO.id", - level = CrmPermissionLevelEnum.WRITE) - // TODO @商机待定:操作日志; + @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", + success = CRM_BUSINESS_UPDATE_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) public void updateBusiness(CrmBusinessUpdateReqVO updateReqVO) { // 1. 校验存在 - validateBusinessExists(updateReqVO.getId()); + CrmBusinessDO oldBusiness = validateBusinessExists(updateReqVO.getId()); // 2. 更新商机 CrmBusinessDO updateObj = CrmBusinessConvert.INSTANCE.convert(updateReqVO); @@ -78,20 +87,28 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { // TODO 商机待定:插入商机与产品的关联表;校验商品存在 // TODO @商机待定:如果状态发生变化,插入商机状态变更记录表 + // 3. 记录操作日志上下文 + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldBusiness, CrmBusinessUpdateReqVO.class)); + LogRecordContext.putVariable("businessName", oldBusiness.getName()); } @Override @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_DELETE_SUB_TYPE, bizNo = "{{#id}}", + success = CRM_BUSINESS_DELETE_SUCCESS) @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) public void deleteBusiness(Long id) { // 校验存在 - validateBusinessExists(id); + CrmBusinessDO business = validateBusinessExists(id); // TODO @商机待定:需要校验有没关联合同。CrmContractDO 的 businessId 字段 // 删除 businessMapper.deleteById(id); // 删除数据权限 permissionService.deletePermission(CrmBizTypeEnum.CRM_BUSINESS.getType(), id); + + // 记录操作日志上下文 + LogRecordContext.putVariable("businessName", business.getName()); } private CrmBusinessDO validateBusinessExists(Long id) { @@ -102,6 +119,28 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { return crmBusiness; } + + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}", + success = CRM_BUSINESS_TRANSFER_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) + public void transferBusiness(CrmBusinessTransferReqVO reqVO, Long userId) { + // 1 校验商机是否存在 + CrmBusinessDO business = validateBusinessExists(reqVO.getId()); + + // 2.1 数据权限转移 + permissionService.transferPermission( + CrmBusinessConvert.INSTANCE.convert(reqVO, userId).setBizType(CrmBizTypeEnum.CRM_BUSINESS.getType())); + // 2.2 设置新的负责人 + businessMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId()); + + // 记录操作日志上下文 + LogRecordContext.putVariable("business", business); + } + + //======================= 查询相关 ======================= + @Override @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#id", level = CrmPermissionLevelEnum.READ) public CrmBusinessDO getBusiness(Long id) { @@ -142,17 +181,8 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { } @Override - @Transactional(rollbackFor = Exception.class) - // TODO @puhui999:操作日志 - public void transferBusiness(CrmBusinessTransferReqVO reqVO, Long userId) { - // 1 校验商机是否存在 - validateBusinessExists(reqVO.getId()); - - // 2.1 数据权限转移 - permissionService.transferPermission( - CrmBusinessConvert.INSTANCE.convert(reqVO, userId).setBizType(CrmBizTypeEnum.CRM_BUSINESS.getType())); - // 2.2 设置新的负责人 - businessMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId()); + public Long getBusinessCountByCustomerId(Long customerId) { + return businessMapper.selectCount(CrmBusinessDO::getCustomerId, customerId); } } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java index 7c169730b..9874f278c 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java @@ -3,12 +3,13 @@ package cn.iocoder.yudao.module.crm.service.clue; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil; 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.clue.vo.CrmCluePageReqVO; import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueSaveReqVO; import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueTransferReqVO; import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueTransformReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerSaveReqVO; import cn.iocoder.yudao.module.crm.convert.clue.CrmClueConvert; -import cn.iocoder.yudao.module.crm.convert.customer.CrmCustomerConvert; import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; import cn.iocoder.yudao.module.crm.dal.mysql.clue.CrmClueMapper; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; @@ -139,8 +140,9 @@ public class CrmClueServiceImpl implements CrmClueService { // 遍历线索,创建对应的客户 clues.forEach(clue -> { + clue.setId(null); // 创建客户 - customerService.createCustomer(CrmCustomerConvert.INSTANCE.convert(clue), userId); + customerService.createCustomer(BeanUtils.toBean(clue, CrmCustomerSaveReqVO.class), userId); // 更新线索状态 // TODO @min:新建一个 CrmClueDO 去更新。尽量规避直接用原本的对象去更新。因为这样万一并发更新,会存在覆盖的问题。 // TODO @puhui999:如果有跟进记录,需要一起转过去; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactService.java index c4432b14a..5235dae4f 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactService.java @@ -1,7 +1,9 @@ package cn.iocoder.yudao.module.crm.service.contact; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.*; +import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactSaveReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactTransferReqVO; import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; import jakarta.validation.Valid; @@ -39,6 +41,22 @@ public interface CrmContactService { */ void deleteContact(Long id); + /** + * 联系人转移 + * + * @param reqVO 请求 + * @param userId 用户编号 + */ + void transferContact(CrmContactTransferReqVO reqVO, Long userId); + + /** + * 更新客户联系人负责人 + * + * @param customerId 客户编号 + * @param ownerUserId 用户编号 + */ + void updateOwnerUserIdByCustomerId(Long customerId, Long ownerUserId); + /** * 获得联系人 * @@ -85,11 +103,11 @@ public interface CrmContactService { PageResult getContactPageByCustomerId(CrmContactPageReqVO pageVO); /** - * 联系人转移 + * 获取关联客户的联系人数量 * - * @param reqVO 请求 - * @param userId 用户编号 + * @param customerId 客户编号 + * @return 数量 */ - void transferContact(CrmContactTransferReqVO reqVO, Long userId); + Long getContactCountByCustomerId(Long customerId); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java index 655190ab3..1597fa131 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java @@ -33,7 +33,7 @@ import java.util.List; 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.CRM_CONTACT_TYPE; +import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_NOT_EXISTS; import static java.util.Collections.singletonList; @@ -65,7 +65,8 @@ public class CrmContactServiceImpl implements CrmContactService { @Override @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CONTACT_TYPE, subType = "创建联系人", bizNo = "{{#contactId}}", success = "创建了联系人[{{#contactName}}]") + @LogRecord(type = CRM_CONTACT_TYPE, subType = CRM_CONTACT_CREATE_SUB_TYPE, bizNo = "{{#contact.id}}", + success = CRM_CONTACT_CREATE_SUCCESS) public Long createContact(CrmContactSaveReqVO createReqVO, Long userId) { // 1. 校验 validateRelationDataExists(createReqVO); @@ -86,18 +87,18 @@ public class CrmContactServiceImpl implements CrmContactService { } // 5. 记录操作日志 - LogRecordContext.putVariable("contactId", contact.getId()); - LogRecordContext.putVariable("contactName", contact.getName()); + LogRecordContext.putVariable("contact", contact); return contact.getId(); } @Override @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CONTACT_TYPE, subType = "更新联系人", bizNo = "{{#updateReqVO.id}}", success = "更新了联系人{_DIFF{#updateReqVO}}") + @LogRecord(type = CRM_CONTACT_TYPE, subType = CRM_CONTACT_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", + success = CRM_CONTACT_UPDATE_SUCCESS) @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) public void updateContact(CrmContactSaveReqVO updateReqVO) { // 1. 校验存在 - CrmContactDO contactDO = validateContactExists(updateReqVO.getId()); + CrmContactDO oldContact = validateContactExists(updateReqVO.getId()); validateRelationDataExists(updateReqVO); // 2. 更新联系人 @@ -105,7 +106,8 @@ public class CrmContactServiceImpl implements CrmContactService { contactMapper.updateById(updateObj); // 3. 记录操作日志 - LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(contactDO, CrmContactSaveReqVO.class)); + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldContact, CrmContactSaveReqVO.class)); + LogRecordContext.putVariable("contactName", oldContact.getName()); } /** @@ -133,11 +135,13 @@ public class CrmContactServiceImpl implements CrmContactService { } @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CONTACT_TYPE, subType = CRM_CONTACT_DELETE_SUB_TYPE, bizNo = "{{#id}}", + success = CRM_CONTACT_DELETE_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) public void deleteContact(Long id) { // 1.1 校验存在 - validateContactExists(id); + CrmContactDO contact = validateContactExists(id); // 1.2 校验是否关联合同 if (contractService.getContractCountByContactId(id) > 0) { throw exception(CONTACT_DELETE_FAIL_CONTRACT_LINK_EXISTS); @@ -151,6 +155,9 @@ public class CrmContactServiceImpl implements CrmContactService { // 4.2 删除商机关联 contactBusinessService.deleteContactBusinessByContactId(id); // TODO @puhui999:删除跟进记录 + + // 记录操作日志上下文 + LogRecordContext.putVariable("contactName", contact.getName()); } private CrmContactDO validateContactExists(Long id) { @@ -161,6 +168,32 @@ public class CrmContactServiceImpl implements CrmContactService { return contactDO; } + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CONTACT_TYPE, subType = CRM_CONTACT_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}", + success = CRM_CONTACT_TRANSFER_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) + public void transferContact(CrmContactTransferReqVO reqVO, Long userId) { + // 1 校验联系人是否存在 + CrmContactDO contact = validateContactExists(reqVO.getId()); + + // 2.1 数据权限转移 + permissionService.transferPermission( + CrmContactConvert.INSTANCE.convert(reqVO, userId).setBizType(CrmBizTypeEnum.CRM_CONTACT.getType())); + // 2.2 设置新的负责人 + contactMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId()); + + // 3. 记录转移日志 + LogRecordContext.putVariable("contact", contact); + } + + @Override + public void updateOwnerUserIdByCustomerId(Long customerId, Long ownerUserId) { + contactMapper.updateOwnerUserIdByCustomerId(customerId, ownerUserId); + } + + //======================= 查询相关 ======================= + @Override @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#id", level = CrmPermissionLevelEnum.READ) public CrmContactDO getContact(Long id) { @@ -192,19 +225,8 @@ public class CrmContactServiceImpl implements CrmContactService { } @Override - // TODO @puhui999:权限校验 - // TODO @puhui999:记录操作日志;将联系人【名字】转移给【新负责人】 - public void transferContact(CrmContactTransferReqVO reqVO, Long userId) { - // 1 校验联系人是否存在 - validateContactExists(reqVO.getId()); - - // 2.1 数据权限转移 - permissionService.transferPermission( - CrmContactConvert.INSTANCE.convert(reqVO, userId).setBizType(CrmBizTypeEnum.CRM_CONTACT.getType())); - // 2.2 设置新的负责人 - contactMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId()); - - // 3. TODO 记录转移日志 + public Long getContactCountByCustomerId(Long customerId) { + return contactMapper.selectCount(CrmContactDO::getCustomerId, customerId); } } \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java index 657a911d8..2490dce02 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java @@ -95,4 +95,12 @@ public interface CrmContractService { */ Long getContractCountByContactId(Long contactId); + /** + * 获取关联客户的合同数量 + * + * @param customerId 客户编号 + * @return 数量 + */ + Long getContractCountByCustomerId(Long customerId); + } 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 489f49bfc..75b71b228 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 @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.crm.service.contract; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil; 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.contract.vo.CrmContractCreateReqVO; import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageReqVO; import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTransferReqVO; @@ -15,6 +16,9 @@ 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.service.permission.CrmPermissionService; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; +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; @@ -25,6 +29,7 @@ import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CONTRACT_NOT_EXISTS; +import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; /** * CRM 合同 Service 实现类 @@ -42,7 +47,9 @@ public class CrmContractServiceImpl implements CrmContractService { private CrmPermissionService crmPermissionService; @Override - // TODO @puhui999:添加操作日志 + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_CREATE_SUB_TYPE, bizNo = "{{#contract.id}}", + success = CRM_CONTRACT_CREATE_SUCCESS) public Long createContract(CrmContractCreateReqVO createReqVO, Long userId) { // TODO @合同待定:插入合同商品;需要搞个 BusinessProductDO // 插入合同 @@ -53,38 +60,52 @@ public class CrmContractServiceImpl implements CrmContractService { crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(userId) .setBizType(CrmBizTypeEnum.CRM_CONTRACT.getType()).setBizId(contract.getId()) .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); + + // 4. 记录操作日志上下文 + LogRecordContext.putVariable("contract", contract); return contract.getId(); } @Override @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", + success = CRM_CONTRACT_UPDATE_SUCCESS) @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) - // TODO @puhui999:添加操作日志 public void updateContract(CrmContractUpdateReqVO updateReqVO) { // TODO @合同待定:只有草稿、审批中,可以编辑; // 校验存在 - validateContractExists(updateReqVO.getId()); + CrmContractDO oldContract = validateContractExists(updateReqVO.getId()); // 更新合同 CrmContractDO updateObj = CrmContractConvert.INSTANCE.convert(updateReqVO); contractMapper.updateById(updateObj); // TODO @合同待定:插入合同商品;需要搞个 BusinessProductDO + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldContract, CrmContractUpdateReqVO.class)); + LogRecordContext.putVariable("contractName", oldContract.getName()); } // TODO @合同待定:缺一个取消合同的接口;只有草稿、审批中可以取消;CrmAuditStatusEnum // TODO @合同待定:缺一个发起审批的接口;只有草稿可以发起审批;CrmAuditStatusEnum + @Override @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_DELETE_SUB_TYPE, bizNo = "{{#id}}", + success = CRM_CONTRACT_DELETE_SUCCESS) @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) public void deleteContract(Long id) { // TODO @合同待定:如果被 CrmReceivableDO 所使用,则不允许删除 // 校验存在 - validateContractExists(id); + CrmContractDO contract = validateContractExists(id); // 删除 contractMapper.deleteById(id); // 删除数据权限 crmPermissionService.deletePermission(CrmBizTypeEnum.CRM_CONTRACT.getType(), id); + + // 记录操作日志上下文 + LogRecordContext.putVariable("contractName", contract.getName()); } private CrmContractDO validateContractExists(Long id) { @@ -95,6 +116,27 @@ public class CrmContractServiceImpl implements CrmContractService { return contract; } + @Override + @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}", + success = CRM_CONTRACT_TRANSFER_SUCCESS) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) + public void transferContract(CrmContractTransferReqVO reqVO, Long userId) { + // 1. 校验合同是否存在 + CrmContractDO contract = validateContractExists(reqVO.getId()); + + // 2.1 数据权限转移 + crmPermissionService.transferPermission( + CrmContractConvert.INSTANCE.convert(reqVO, userId).setBizType(CrmBizTypeEnum.CRM_CONTRACT.getType())); + // 2.2 设置负责人 + contractMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId()); + + // 3. 记录转移日志 + LogRecordContext.putVariable("contract", contract); + } + + //======================= 查询相关 ======================= + @Override @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#id", level = CrmPermissionLevelEnum.READ) public CrmContractDO getContract(Long id) { @@ -120,25 +162,15 @@ public class CrmContractServiceImpl implements CrmContractService { return contractMapper.selectPageByCustomerId(pageReqVO); } - @Override - @Transactional(rollbackFor = Exception.class) - // 3. TODO @puhui999:记录转移日志 - // TODO @puhui999:权限校验,这里要搞哇? - public void transferContract(CrmContractTransferReqVO reqVO, Long userId) { - // 1. 校验合同是否存在 - validateContractExists(reqVO.getId()); - - // 2.1 数据权限转移 - crmPermissionService.transferPermission( - CrmContractConvert.INSTANCE.convert(reqVO, userId).setBizType(CrmBizTypeEnum.CRM_CONTRACT.getType())); - // 2.2 设置负责人 - contractMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId()); - } - @Override public Long getContractCountByContactId(Long contactId) { return contractMapper.selectCountByContactId(contactId); } + @Override + public Long getContractCountByCustomerId(Long customerId) { + return contractMapper.selectCount(CrmContractDO::getCustomerId, customerId); + } + // TODO @合同待定:需要新增一个 ContractConfigDO 表,合同配置,重点是到期提醒; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerLimitConfigServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerLimitConfigServiceImpl.java index cc71bac0c..d232f307d 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerLimitConfigServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerLimitConfigServiceImpl.java @@ -5,7 +5,6 @@ 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.customer.vo.limitconfig.CrmCustomerLimitConfigPageReqVO; import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigSaveReqVO; -import cn.iocoder.yudao.module.crm.convert.customer.CrmCustomerLimitConfigConvert; import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerLimitConfigDO; import cn.iocoder.yudao.module.crm.dal.mysql.customer.CrmCustomerLimitConfigMapper; import cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLimitConfigTypeEnum; @@ -49,7 +48,7 @@ public class CrmCustomerLimitConfigServiceImpl implements CrmCustomerLimitConfig public Long createCustomerLimitConfig(CrmCustomerLimitConfigSaveReqVO createReqVO) { validateUserAndDept(createReqVO.getUserIds(), createReqVO.getDeptIds()); // 插入 - CrmCustomerLimitConfigDO customerLimitConfig = CrmCustomerLimitConfigConvert.INSTANCE.convert(createReqVO); + CrmCustomerLimitConfigDO customerLimitConfig = BeanUtils.toBean(createReqVO, CrmCustomerLimitConfigDO.class); customerLimitConfigMapper.insert(customerLimitConfig); // 记录操作日志上下文 @@ -66,7 +65,7 @@ public class CrmCustomerLimitConfigServiceImpl implements CrmCustomerLimitConfig CrmCustomerLimitConfigDO oldLimitConfig = validateCustomerLimitConfigExists(updateReqVO.getId()); validateUserAndDept(updateReqVO.getUserIds(), updateReqVO.getDeptIds()); // 更新 - CrmCustomerLimitConfigDO updateObj = CrmCustomerLimitConfigConvert.INSTANCE.convert(updateReqVO); + CrmCustomerLimitConfigDO updateObj = BeanUtils.toBean(updateReqVO, CrmCustomerLimitConfigDO.class); customerLimitConfigMapper.updateById(updateObj); // 记录操作日志上下文 diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerPoolConfigServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerPoolConfigServiceImpl.java index 2a0e5ade9..303a758d2 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerPoolConfigServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerPoolConfigServiceImpl.java @@ -1,8 +1,7 @@ package cn.iocoder.yudao.module.crm.service.customer; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.poolconfig.CrmCustomerPoolConfigSaveReqVO; -import cn.iocoder.yudao.module.crm.convert.customer.CrmCustomerConvert; import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; import cn.iocoder.yudao.module.crm.dal.mysql.customer.CrmCustomerPoolConfigMapper; import com.mzt.logapi.context.LogRecordContext; @@ -34,8 +33,7 @@ public class CrmCustomerPoolConfigServiceImpl implements CrmCustomerPoolConfigSe */ @Override public CrmCustomerPoolConfigDO getCustomerPoolConfig() { - // TODO @puhui999:这个要搞到 mapper 里噢。 - return customerPoolConfigMapper.selectOne(new LambdaQueryWrapperX().last("LIMIT 1")); + return customerPoolConfigMapper.selectOne(); } /** @@ -49,7 +47,7 @@ public class CrmCustomerPoolConfigServiceImpl implements CrmCustomerPoolConfigSe public void saveCustomerPoolConfig(CrmCustomerPoolConfigSaveReqVO saveReqVO) { // 存在,则进行更新 CrmCustomerPoolConfigDO dbConfig = getCustomerPoolConfig(); - CrmCustomerPoolConfigDO poolConfig = CrmCustomerConvert.INSTANCE.convert(saveReqVO); + CrmCustomerPoolConfigDO poolConfig = BeanUtils.toBean(saveReqVO, CrmCustomerPoolConfigDO.class); if (Objects.nonNull(dbConfig)) { customerPoolConfigMapper.updateById(poolConfig.setId(dbConfig.getId())); // 记录操作日志上下文 diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java index a18f65d33..4b0e550cc 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java @@ -18,6 +18,9 @@ import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; 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.util.CrmPermissionUtils; +import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; +import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; +import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; 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; @@ -26,6 +29,7 @@ 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.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -59,6 +63,15 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { private CrmPermissionService permissionService; @Resource private CrmCustomerLimitConfigService customerLimitConfigService; + @Resource + @Lazy + private CrmContactService contactService; + @Resource + @Lazy + private CrmBusinessService businessService; + @Resource + @Lazy + private CrmContractService contractService; @Resource private AdminUserApi adminUserApi; @@ -73,7 +86,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { validateCustomerExceedOwnerLimit(createReqVO.getOwnerUserId(), 1); // 2. 插入客户 - CrmCustomerDO customer = CrmCustomerConvert.INSTANCE.convert(createReqVO) + CrmCustomerDO customer = BeanUtils.toBean(createReqVO, CrmCustomerDO.class) .setLockStatus(false).setDealStatus(false) .setContactLastTime(LocalDateTime.now()); // TODO @puhui999:可能要加个 receiveTime 字段,记录最后接收时间 @@ -100,7 +113,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { CrmCustomerDO oldCustomer = validateCustomerExists(updateReqVO.getId()); // 2. 更新客户 - CrmCustomerDO updateObj = CrmCustomerConvert.INSTANCE.convert(updateReqVO); + CrmCustomerDO updateObj = BeanUtils.toBean(updateReqVO, CrmCustomerDO.class); customerMapper.updateById(updateObj); // 3. 记录操作日志上下文 @@ -116,8 +129,8 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { public void deleteCustomer(Long id) { // 校验存在 CrmCustomerDO customer = validateCustomerExists(id); - // TODO @puhui999:如果有联系人、商机,则不允许删除; - + // 检查引用 + checkCustomerReference(id); // 删除 customerMapper.deleteById(id); // 删除数据权限 @@ -128,6 +141,23 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { LogRecordContext.putVariable("customerName", customer.getName()); } + /** + * 校验客户是否被引用 + * + * @param id 客户编号 + */ + private void checkCustomerReference(Long id) { + if (contactService.getContactCountByCustomerId(id) > 0) { + throw exception(CUSTOMER_DELETE_FAIL_HAVE_REFERENCE, CrmBizTypeEnum.CRM_CONTACT.getName()); + } + if (businessService.getBusinessCountByCustomerId(id) > 0) { + throw exception(CUSTOMER_DELETE_FAIL_HAVE_REFERENCE, CrmBizTypeEnum.CRM_BUSINESS.getName()); + } + if (contractService.getContractCountByCustomerId(id) > 0) { + throw exception(CUSTOMER_DELETE_FAIL_HAVE_REFERENCE, CrmBizTypeEnum.CRM_CONTRACT.getName()); + } + } + @Override @Transactional(rollbackFor = Exception.class) @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}", @@ -145,10 +175,8 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { // 2.2 转移后重新设置负责人 customerMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId()); - // 3. TODO 记录转移日志 - // 记录操作日志上下文 - // TODO @puhui999:crmCustomer=》customer,也看看其他有没类似的情况哈 - LogRecordContext.putVariable("crmCustomer", customer); + // 3. 记录转移日志 + LogRecordContext.putVariable("customer", customer); } @Override @@ -172,7 +200,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { // 3. 记录操作日志上下文 // tips: 因为这里使用的是老的状态所以记录时反着记录,也就是 lockStatus 为 true 那么就是解锁反之为锁定 - LogRecordContext.putVariable("crmCustomer", customer); + LogRecordContext.putVariable("customer", customer); } // ==================== 公海相关操作 ==================== @@ -202,6 +230,8 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { permissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), customer.getId(), CrmPermissionLevelEnum.OWNER.getLevel()); // TODO @puhui999:联系人的负责人,也要设置为 null;这块和领取是对应的;因为领取后,负责人也要关联过来; + // 提问:那是不是可以这样理解客户所有联系人的负责人默认为客户的负责人,然后添加客户团队成员时才存在“同时分配给”的操作? + contactService.updateOwnerUserIdByCustomerId(customer.getId(), null); // 记录操作日志上下文 LogRecordContext.putVariable("customerName", customer.getName()); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordService.java new file mode 100644 index 000000000..35fdf9e52 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordService.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.crm.service.followup; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.followup.CrmFollowUpRecordDO; +import jakarta.validation.Valid; + +/** + * 跟进记录 Service 接口 + * + * @author 芋道源码 + */ +public interface CrmFollowUpRecordService { + + /** + * 创建跟进记录 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createFollowUpRecord(@Valid CrmFollowUpRecordSaveReqVO createReqVO); + + /** + * 更新跟进记录 + * + * @param updateReqVO 更新信息 + */ + void updateFollowUpRecord(@Valid CrmFollowUpRecordSaveReqVO updateReqVO); + + /** + * 删除跟进记录 + * + * @param id 编号 + */ + void deleteFollowUpRecord(Long id); + + /** + * 获得跟进记录 + * + * @param id 编号 + * @return 跟进记录 + */ + CrmFollowUpRecordDO getFollowUpRecord(Long id); + + /** + * 获得跟进记录分页 + * + * @param pageReqVO 分页查询 + * @return 跟进记录分页 + */ + PageResult getFollowUpRecordPage(CrmFollowUpRecordPageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordServiceImpl.java new file mode 100644 index 000000000..5742791e4 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordServiceImpl.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.crm.service.followup; + +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.followup.vo.CrmFollowUpRecordPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.followup.CrmFollowUpRecordDO; +import cn.iocoder.yudao.module.crm.dal.mysql.followup.CrmFollowUpRecordMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.FOLLOW_UP_RECORD_NOT_EXISTS; + +/** + * 跟进记录 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class CrmFollowUpRecordServiceImpl implements CrmFollowUpRecordService { + + @Resource + private CrmFollowUpRecordMapper crmFollowUpRecordMapper; + + @Override + public Long createFollowUpRecord(CrmFollowUpRecordSaveReqVO createReqVO) { + // 插入 + CrmFollowUpRecordDO followUpRecord = BeanUtils.toBean(createReqVO, CrmFollowUpRecordDO.class); + crmFollowUpRecordMapper.insert(followUpRecord); + // 返回 + return followUpRecord.getId(); + } + + @Override + public void updateFollowUpRecord(CrmFollowUpRecordSaveReqVO updateReqVO) { + // 校验存在 + validateFollowUpRecordExists(updateReqVO.getId()); + // 更新 + CrmFollowUpRecordDO updateObj = BeanUtils.toBean(updateReqVO, CrmFollowUpRecordDO.class); + crmFollowUpRecordMapper.updateById(updateObj); + } + + @Override + public void deleteFollowUpRecord(Long id) { + // 校验存在 + validateFollowUpRecordExists(id); + // 删除 + crmFollowUpRecordMapper.deleteById(id); + } + + private void validateFollowUpRecordExists(Long id) { + if (crmFollowUpRecordMapper.selectById(id) == null) { + throw exception(FOLLOW_UP_RECORD_NOT_EXISTS); + } + } + + @Override + public CrmFollowUpRecordDO getFollowUpRecord(Long id) { + return crmFollowUpRecordMapper.selectById(id); + } + + @Override + public PageResult getFollowUpRecordPage(CrmFollowUpRecordPageReqVO pageReqVO) { + return crmFollowUpRecordMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java index 854bf90a1..e8a74d49f 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java @@ -20,6 +20,7 @@ import org.springframework.validation.annotation.Validated; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Set; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; @@ -36,7 +37,7 @@ import static cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnu public class CrmPermissionServiceImpl implements CrmPermissionService { @Resource - private CrmPermissionMapper crmPermissionMapper; + private CrmPermissionMapper permissionMapper; @Resource private AdminUserApi adminUserApi; @@ -44,50 +45,59 @@ public class CrmPermissionServiceImpl implements CrmPermissionService { @Override @Transactional(rollbackFor = Exception.class) public Long createPermission(CrmPermissionCreateReqBO createReqBO) { - // TODO @puhui999:排重 + validatePermissionNotExists(Collections.singletonList(createReqBO)); // 1. 校验用户是否存在 adminUserApi.validateUserList(Collections.singletonList(createReqBO.getUserId())); // 2. 创建 CrmPermissionDO permission = CrmPermissionConvert.INSTANCE.convert(createReqBO); - crmPermissionMapper.insert(permission); + permissionMapper.insert(permission); return permission.getId(); } @Override public void createPermissionBatch(List createReqBOs) { - // TODO @puhui999:排重 + validatePermissionNotExists(createReqBOs); // 1. 校验用户是否存在 adminUserApi.validateUserList(convertSet(createReqBOs, CrmPermissionCreateReqBO::getUserId)); // 2. 创建 List permissions = CrmPermissionConvert.INSTANCE.convertList(createReqBOs); - crmPermissionMapper.insertBatch(permissions); + permissionMapper.insertBatch(permissions); } @Override @Transactional(rollbackFor = Exception.class) public void updatePermission(CrmPermissionUpdateReqVO updateReqVO) { - // TODO @puhui999:排重 // 1. 校验存在 - validateCrmPermissionExists(updateReqVO.getIds()); + validatePermissionExists(updateReqVO.getIds()); // 2. 更新 List updateDO = CrmPermissionConvert.INSTANCE.convertList(updateReqVO); - crmPermissionMapper.updateBatch(updateDO); + permissionMapper.updateBatch(updateDO); } - private void validateCrmPermissionExists(Collection ids) { - List permissionList = crmPermissionMapper.selectBatchIds(ids); + private void validatePermissionExists(Collection ids) { + List permissionList = permissionMapper.selectBatchIds(ids); if (ObjUtil.notEqual(permissionList.size(), ids.size())) { throw exception(CRM_PERMISSION_NOT_EXISTS); } } + private void validatePermissionNotExists(Collection createReqBOs) { + Set bizTypes = convertSet(createReqBOs, CrmPermissionCreateReqBO::getBizType); + Set bizIds = convertSet(createReqBOs, CrmPermissionCreateReqBO::getBizId); + Set userIds = convertSet(createReqBOs, CrmPermissionCreateReqBO::getUserId); + Long count = permissionMapper.selectListByBiz(bizTypes, bizIds, userIds); + if (count > 0) { + throw exception(CRM_PERMISSION_CREATE_FAIL); + } + } + @Override @Transactional(rollbackFor = Exception.class) public void transferPermission(CrmPermissionTransferReqBO transferReqBO) { // 1. 校验数据权限:是否是负责人,只有负责人才可以转移 - CrmPermissionDO oldPermission = crmPermissionMapper.selectByBizTypeAndBizIdByUserId( + CrmPermissionDO oldPermission = permissionMapper.selectByBizTypeAndBizIdByUserId( transferReqBO.getBizType(), transferReqBO.getBizId(), transferReqBO.getUserId()); String bizTypeName = CrmBizTypeEnum.getNameByType(transferReqBO.getBizType()); if (oldPermission == null // 不是拥有者,并且不是超管 @@ -102,25 +112,25 @@ public class CrmPermissionServiceImpl implements CrmPermissionService { adminUserApi.validateUserList(Collections.singletonList(transferReqBO.getNewOwnerUserId())); // 2. 修改新负责人的权限 - List permissions = crmPermissionMapper.selectByBizTypeAndBizId( + List permissions = permissionMapper.selectByBizTypeAndBizId( transferReqBO.getBizType(), transferReqBO.getBizId()); // 获得所有数据权限 CrmPermissionDO permission = CollUtil.findOne(permissions, item -> ObjUtil.equal(item.getUserId(), transferReqBO.getNewOwnerUserId())); if (permission == null) { - crmPermissionMapper.insert(new CrmPermissionDO().setBizType(transferReqBO.getBizType()) + permissionMapper.insert(new CrmPermissionDO().setBizType(transferReqBO.getBizType()) .setBizId(transferReqBO.getBizId()).setUserId(transferReqBO.getNewOwnerUserId()) .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); } else { - crmPermissionMapper.updateById(new CrmPermissionDO().setId(permission.getId()) + permissionMapper.updateById(new CrmPermissionDO().setId(permission.getId()) .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); } // 3. 修改老负责人的权限 if (transferReqBO.getOldOwnerPermissionLevel() != null) { - crmPermissionMapper.updateById(new CrmPermissionDO().setId(oldPermission.getId()) + permissionMapper.updateById(new CrmPermissionDO().setId(oldPermission.getId()) .setLevel(transferReqBO.getOldOwnerPermissionLevel())); } else { - crmPermissionMapper.deleteById(oldPermission.getId()); + permissionMapper.deleteById(oldPermission.getId()); } } @@ -128,19 +138,19 @@ public class CrmPermissionServiceImpl implements CrmPermissionService { @Transactional(rollbackFor = Exception.class) public void deletePermission(Integer bizType, Long bizId, Integer level) { // 校验存在 - List permissions = crmPermissionMapper.selectListByBizTypeAndBizIdAndLevel( + List permissions = permissionMapper.selectListByBizTypeAndBizIdAndLevel( bizType, bizId, level); if (CollUtil.isEmpty(permissions)) { throw exception(CRM_PERMISSION_NOT_EXISTS); } // 删除数据权限 - crmPermissionMapper.deleteBatchIds(convertSet(permissions, CrmPermissionDO::getId)); + permissionMapper.deleteBatchIds(convertSet(permissions, CrmPermissionDO::getId)); } @Override public void deletePermission(Integer bizType, Long bizId) { - int deletedCount = crmPermissionMapper.deletePermission(bizType, bizId); + int deletedCount = permissionMapper.deletePermission(bizType, bizId); if (deletedCount == 0) { throw exception(CRM_PERMISSION_NOT_EXISTS); } @@ -148,7 +158,7 @@ public class CrmPermissionServiceImpl implements CrmPermissionService { @Override public void deletePermissionBatch(Collection ids, Long userId) { - List permissions = crmPermissionMapper.selectBatchIds(ids); + List permissions = permissionMapper.selectBatchIds(ids); if (CollUtil.isEmpty(permissions)) { throw exception(CRM_PERMISSION_NOT_EXISTS); } @@ -157,19 +167,19 @@ public class CrmPermissionServiceImpl implements CrmPermissionService { throw exception(CRM_PERMISSION_DELETE_FAIL); } // 校验操作人是否为负责人 - CrmPermissionDO permission = crmPermissionMapper.selectByIdAndUserId(permissions.get(0).getBizId(), userId); + CrmPermissionDO permission = permissionMapper.selectByIdAndUserId(permissions.get(0).getBizId(), userId); if (!CrmPermissionLevelEnum.isOwner(permission.getLevel())) { throw exception(CRM_PERMISSION_DELETE_DENIED); } // 删除数据权限 - crmPermissionMapper.deleteBatchIds(ids); + permissionMapper.deleteBatchIds(ids); } @Override public void deleteSelfPermission(Long id, Long userId) { // 校验数据存在且是自己 - CrmPermissionDO permission = crmPermissionMapper.selectByIdAndUserId(id, userId); + CrmPermissionDO permission = permissionMapper.selectByIdAndUserId(id, userId); if (permission == null) { throw exception(CRM_PERMISSION_NOT_EXISTS); } @@ -179,22 +189,22 @@ public class CrmPermissionServiceImpl implements CrmPermissionService { } // 删除 - crmPermissionMapper.deleteById(id); + permissionMapper.deleteById(id); } @Override public List getPermissionListByBiz(Integer bizType, Long bizId) { - return crmPermissionMapper.selectByBizTypeAndBizId(bizType, bizId); + return permissionMapper.selectByBizTypeAndBizId(bizType, bizId); } @Override public List getPermissionListByBiz(Integer bizType, Collection bizIds) { - return crmPermissionMapper.selectByBizTypeAndBizIds(bizType, bizIds); + return permissionMapper.selectByBizTypeAndBizIds(bizType, bizIds); } @Override public List getPermissionListByBizTypeAndUserId(Integer bizType, Long userId) { - return crmPermissionMapper.selectListByBizTypeAndUserId(bizType, userId); + return permissionMapper.selectListByBizTypeAndUserId(bizType, userId); } } 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 93d05e651..ded059b28 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 @@ -3,7 +3,6 @@ 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.plan.CrmReceivablePlanCreateReqVO; import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanPageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanTransferReqVO; import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanUpdateReqVO; import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO; @@ -78,12 +77,4 @@ public interface CrmReceivablePlanService { */ PageResult getReceivablePlanPageByCustomerId(CrmReceivablePlanPageReqVO pageReqVO); - /** - * 回款计划转移 - * - * @param reqVO 请求 - * @param userId 用户编号 - */ - void transferReceivablePlan(CrmReceivablePlanTransferReqVO reqVO, Long userId); - } 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 453c82d39..d05647cfb 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 @@ -4,9 +4,9 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.util.ObjectUtil; 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.plan.CrmReceivablePlanCreateReqVO; import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanPageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanTransferReqVO; import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanUpdateReqVO; import cn.iocoder.yudao.module.crm.convert.receivable.CrmReceivablePlanConvert; import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; @@ -20,6 +20,9 @@ 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 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.validation.annotation.Validated; @@ -29,6 +32,7 @@ import java.util.List; 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.*; // TODO @liuhongfeng:参考 CrmReceivableServiceImpl 写的 todo 哈; @@ -49,10 +53,11 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService { @Resource private CrmCustomerService customerService; @Resource - private CrmPermissionService crmPermissionService; + private CrmPermissionService permissionService; @Override - // TODO @puhui999:操作日志 + @LogRecord(type = CRM_RECEIVABLE_PLAN_TYPE, subType = CRM_RECEIVABLE_PLAN_CREATE_SUB_TYPE, bizNo = "{{#receivablePlan.id}}", + success = CRM_RECEIVABLE_PLAN_CREATE_SUCCESS) public Long createReceivablePlan(CrmReceivablePlanCreateReqVO createReqVO, Long userId) { // TODO @liuhongfeng:第几期的计算;基于是 contractId + contractDO 的第几个还款 // TODO @liuhongfeng contractId:校验合同是否存在 @@ -64,9 +69,12 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService { receivablePlanMapper.insert(receivablePlan); // 创建数据权限 - crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(userId) + permissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(userId) .setBizType(CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType()).setBizId(receivablePlan.getId()) .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); + + // 4. 记录操作日志上下文 + LogRecordContext.putVariable("receivablePlan", receivablePlan); return receivablePlan.getId(); } @@ -89,31 +97,44 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService { } @Override + @LogRecord(type = CRM_RECEIVABLE_PLAN_TYPE, subType = CRM_RECEIVABLE_PLAN_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", + success = CRM_RECEIVABLE_PLAN_UPDATE_SUCCESS) @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE_PLAN, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) - // TODO @puhui999:操作日志 public void updateReceivablePlan(CrmReceivablePlanUpdateReqVO updateReqVO) { // TODO @liuhongfeng:如果已经有对应的还款,则不允许编辑; // 校验存在 - validateReceivablePlanExists(updateReqVO.getId()); + CrmReceivablePlanDO oldReceivablePlan = validateReceivablePlanExists(updateReqVO.getId()); // 更新 CrmReceivablePlanDO updateObj = CrmReceivablePlanConvert.INSTANCE.convert(updateReqVO); receivablePlanMapper.updateById(updateObj); + + // 3. 记录操作日志上下文 + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldReceivablePlan, CrmReceivablePlanUpdateReqVO.class)); + LogRecordContext.putVariable("receivablePlan", oldReceivablePlan); } @Override + @LogRecord(type = CRM_RECEIVABLE_PLAN_TYPE, subType = CRM_RECEIVABLE_PLAN_DELETE_SUB_TYPE, bizNo = "{{#id}}", + success = CRM_RECEIVABLE_PLAN_DELETE_SUCCESS) @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE_PLAN, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) public void deleteReceivablePlan(Long id) { // 校验存在 - validateReceivablePlanExists(id); + CrmReceivablePlanDO receivablePlan = validateReceivablePlanExists(id); // 删除 receivablePlanMapper.deleteById(id); + // 删除数据权限 + permissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), id); + // 记录操作日志上下文 + LogRecordContext.putVariable("receivablePlan", receivablePlan); } - private void validateReceivablePlanExists(Long id) { - if (receivablePlanMapper.selectById(id) == null) { + private CrmReceivablePlanDO validateReceivablePlanExists(Long id) { + CrmReceivablePlanDO receivablePlan = receivablePlanMapper.selectById(id); + if (receivablePlan == null) { throw exception(RECEIVABLE_PLAN_NOT_EXISTS); } + return receivablePlan; } @Override @@ -141,19 +162,4 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService { return receivablePlanMapper.selectPageByCustomerId(pageReqVO); } - // TODO @puhui999:这个没有 transfer 接口;可能是的哈 - @Override - public void transferReceivablePlan(CrmReceivablePlanTransferReqVO reqVO, Long userId) { - // 1 校验回款计划是否存在 - validateReceivablePlanExists(reqVO.getId()); - - // 2.1 数据权限转移 - crmPermissionService.transferPermission( - CrmReceivablePlanConvert.INSTANCE.convert(reqVO, userId).setBizType(CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType())); - // 2.2 设置新的负责人 - receivablePlanMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId()); - - // 3. TODO 记录转移日志 - } - } 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 79be4b338..8e9cfa0ea 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 @@ -3,7 +3,6 @@ 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.crm.controller.admin.receivable.vo.receivable.CrmReceivablePageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableTransferReqVO; import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableUpdateReqVO; import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO; @@ -23,9 +22,10 @@ public interface CrmReceivableService { * 创建回款 * * @param createReqVO 创建信息 + * @param userId 用户编号 * @return 编号 */ - Long createReceivable(@Valid CrmReceivableCreateReqVO createReqVO); + Long createReceivable(@Valid CrmReceivableCreateReqVO createReqVO, Long userId); /** * 更新回款 @@ -78,12 +78,4 @@ public interface CrmReceivableService { */ PageResult getReceivablePageByCustomerId(CrmReceivablePageReqVO pageReqVO); - /** - * 回款转移 - * - * @param reqVO 请求 - * @param userId 用户编号 - */ - void transferReceivable(CrmReceivableTransferReqVO reqVO, 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 5100ddd6e..860c984d3 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 @@ -5,9 +5,9 @@ import cn.hutool.core.collection.ListUtil; 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.module.crm.controller.admin.receivable.vo.receivable.CrmReceivablePageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableTransferReqVO; 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.dal.dataobject.contract.CrmContractDO; @@ -22,6 +22,10 @@ import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPerm 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 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.validation.annotation.Validated; @@ -31,6 +35,7 @@ import java.util.List; 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.*; /** * CRM 回款 Service 实现类 @@ -51,11 +56,12 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { @Resource private CrmReceivablePlanService receivablePlanService; @Resource - private CrmPermissionService crmPermissionService; + private CrmPermissionService permissionService; @Override - // TODO @puhui999:操作日志 - public Long createReceivable(CrmReceivableCreateReqVO createReqVO) { + @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())) { @@ -67,8 +73,12 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { checkReceivable(receivable); 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 + // 记录操作日志上下文 + LogRecordContext.putVariable("receivable", receivable); return receivable.getId(); } @@ -98,11 +108,12 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { } @Override - // TODO @puhui999:操作日志 - // TODO @puhui999:权限校验 + @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) { // 校验存在 - validateReceivableExists(updateReqVO.getId()); + CrmReceivableDO oldReceivable = validateReceivableExists(updateReqVO.getId()); // TODO @liuhongfeng:只有在草稿、审核中,可以提交修改 // 更新还款 @@ -110,6 +121,9 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { receivableMapper.updateById(updateObj); // TODO @liuhongfeng:需要更新关联的 plan + // 3. 记录操作日志上下文 + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldReceivable, CrmReceivableUpdateReqVO.class)); + LogRecordContext.putVariable("receivable", oldReceivable); } // TODO @liuhongfeng:缺一个取消合同的接口;只有草稿、审批中可以取消;CrmAuditStatusEnum @@ -117,24 +131,33 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { // TODO @liuhongfeng:缺一个发起审批的接口;只有草稿可以发起审批;CrmAuditStatusEnum @Override - // TODO @puhui999:操作日志 - // TODO @puhui999:权限校验 + @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 所使用,则不允许删除 // 校验存在 - validateReceivableExists(id); + CrmReceivableDO receivable = validateReceivableExists(id); // 删除 receivableMapper.deleteById(id); + + // 删除数据权限 + permissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), id); + + // 记录操作日志上下文 + LogRecordContext.putVariable("receivable", receivable); } - private void validateReceivableExists(Long id) { - if (receivableMapper.selectById(id) == null) { + private CrmReceivableDO validateReceivableExists(Long id) { + CrmReceivableDO receivable = receivableMapper.selectById(id); + if (receivable == null) { throw exception(RECEIVABLE_NOT_EXISTS); } + return receivable; } - // TODO @芋艿:数据权限 @Override + @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE, bizId = "#id", level = CrmPermissionLevelEnum.READ) public CrmReceivableDO getReceivable(Long id) { return receivableMapper.selectById(id); } @@ -158,18 +181,4 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { return receivableMapper.selectPageByCustomerId(pageReqVO); } - @Override - public void transferReceivable(CrmReceivableTransferReqVO reqVO, Long userId) { - // 1 校验回款是否存在 - validateReceivableExists(reqVO.getId()); - - // 2.1 数据权限转移 - crmPermissionService.transferPermission( - CrmReceivableConvert.INSTANCE.convert(reqVO, userId).setBizType(CrmBizTypeEnum.CRM_RECEIVABLE.getType())); - // 2.2 设置新的负责人 - receivableMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId()); - - // 3. TODO 记录转移日志 - } - } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/test/java/cn/iocoder/yudao/module/crm/service/receivable/CrmCrmReceivableServiceImplTest.java b/yudao-module-crm/yudao-module-crm-biz/src/test/java/cn/iocoder/yudao/module/crm/service/receivable/CrmCrmReceivableServiceImplTest.java index 1f3d821af..04c466924 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/test/java/cn/iocoder/yudao/module/crm/service/receivable/CrmCrmReceivableServiceImplTest.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/test/java/cn/iocoder/yudao/module/crm/service/receivable/CrmCrmReceivableServiceImplTest.java @@ -13,6 +13,7 @@ import org.junit.jupiter.api.Test; import org.springframework.context.annotation.Import; import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; @@ -42,7 +43,7 @@ public class CrmCrmReceivableServiceImplTest extends BaseDbUnitTest { CrmReceivableCreateReqVO reqVO = randomPojo(CrmReceivableCreateReqVO.class); // 调用 - Long receivableId = receivableService.createReceivable(reqVO); + Long receivableId = receivableService.createReceivable(reqVO, getLoginUserId()); // 断言 assertNotNull(receivableId); // 校验记录的属性是否正确 diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/operatelog/SysParseFunctionNameConstants.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/operatelog/SysParseFunctionNameConstants.java new file mode 100644 index 000000000..dafaa37f6 --- /dev/null +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/operatelog/SysParseFunctionNameConstants.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.system.enums.operatelog; + +/** + * functionName 常量枚举 + * 方便别的模块调用 + * + * @author HUIHUI + */ +public interface SysParseFunctionNameConstants { + + String GET_ADMIN_USER_BY_ID = "getAdminUserById"; // 获取用户信息 + String GET_DEPT_BY_ID = "getDeptById"; // 获取部门信息 + String GET_AREA = "getArea"; // 获取区域信息 + String GET_SEX = "getSex"; // 获取性别 + String GET_BOOLEAN = "getBoolean"; // 获取是否 + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/AdminUserParseFunction.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/AdminUserParseFunction.java index a75ac309b..28bb2e099 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/AdminUserParseFunction.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/AdminUserParseFunction.java @@ -8,6 +8,8 @@ import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import static cn.iocoder.yudao.module.system.enums.operatelog.SysParseFunctionNameConstants.GET_ADMIN_USER_BY_ID; + /** * 管理员名字的 {@link IParseFunction} 实现类 * @@ -22,7 +24,7 @@ public class AdminUserParseFunction implements IParseFunction { @Override public String functionName() { - return "getAdminUserById"; + return GET_ADMIN_USER_BY_ID; } @Override diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/AreaParseFunction.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/AreaParseFunction.java index a114beb2d..3f9bf5a5f 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/AreaParseFunction.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/AreaParseFunction.java @@ -6,6 +6,8 @@ import com.mzt.logapi.service.IParseFunction; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import static cn.iocoder.yudao.module.system.enums.operatelog.SysParseFunctionNameConstants.GET_AREA; + /** * 地名的 {@link IParseFunction} 实现类 * @@ -22,7 +24,7 @@ public class AreaParseFunction implements IParseFunction { @Override public String functionName() { - return "getAreaById"; + return GET_AREA; } @Override diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmBooleanParseFunction.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/BooleanParseFunction.java similarity index 70% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmBooleanParseFunction.java rename to yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/BooleanParseFunction.java index 839ead257..73f462583 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmBooleanParseFunction.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/BooleanParseFunction.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.crm.framework.operatelog.core; +package cn.iocoder.yudao.module.system.framework.operatelog.core; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; @@ -7,16 +7,16 @@ import com.mzt.logapi.service.IParseFunction; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import static cn.iocoder.yudao.module.system.enums.operatelog.SysParseFunctionNameConstants.GET_BOOLEAN; + /** - * 行业的 {@link IParseFunction} 实现类 + * 是否类型的 {@link IParseFunction} 实现类 * * @author HUIHUI */ @Component @Slf4j -public class CrmBooleanParseFunction implements IParseFunction { - - public static final String NAME = "getBooleanById"; +public class BooleanParseFunction implements IParseFunction { @Override public boolean executeBefore() { @@ -25,7 +25,7 @@ public class CrmBooleanParseFunction implements IParseFunction { @Override public String functionName() { - return NAME; + return GET_BOOLEAN; } @Override diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/DeptParseFunction.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/DeptParseFunction.java index 1f9af363d..fee6af243 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/DeptParseFunction.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/DeptParseFunction.java @@ -8,6 +8,8 @@ import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import static cn.iocoder.yudao.module.system.enums.operatelog.SysParseFunctionNameConstants.GET_DEPT_BY_ID; + /** * 管理员名字的 {@link IParseFunction} 实现类 * @@ -22,7 +24,7 @@ public class DeptParseFunction implements IParseFunction { @Override public String functionName() { - return "getDeptById"; + return GET_DEPT_BY_ID; } @Override diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmSexParseFunction.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/SexParseFunction.java similarity index 76% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmSexParseFunction.java rename to yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/SexParseFunction.java index a66f902a8..751f30779 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmSexParseFunction.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/SexParseFunction.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.crm.framework.operatelog.core; +package cn.iocoder.yudao.module.system.framework.operatelog.core; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; @@ -7,6 +7,8 @@ import com.mzt.logapi.service.IParseFunction; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import static cn.iocoder.yudao.module.system.enums.operatelog.SysParseFunctionNameConstants.GET_SEX; + /** * 行业的 {@link IParseFunction} 实现类 * @@ -14,9 +16,7 @@ import org.springframework.stereotype.Component; */ @Component @Slf4j -public class CrmSexParseFunction implements IParseFunction { - - public static final String NAME = "getSexById"; +public class SexParseFunction implements IParseFunction { @Override public boolean executeBefore() { @@ -25,7 +25,7 @@ public class CrmSexParseFunction implements IParseFunction { @Override public String functionName() { - return NAME; + return GET_SEX; } @Override