Przeglądaj źródła

CRM: 完善客户、联系人、合同、回款计划、回款的操作日志

puhui999 1 rok temu
rodzic
commit
1a5fe6fa9a
13 zmienionych plików z 255 dodań i 163 usunięć
  1. 43 3
      yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java
  2. 1 0
      yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/operatelog/CrmParseFunctionNameConstants.java
  3. 5 10
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java
  4. 4 9
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java
  5. 45 20
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java
  6. 37 25
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java
  7. 46 19
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java
  8. 3 5
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java
  9. 0 9
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanService.java
  10. 30 24
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java
  11. 2 10
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java
  12. 37 28
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java
  13. 2 1
      yudao-module-crm/yudao-module-crm-biz/src/test/java/cn/iocoder/yudao/module/crm/service/receivable/CrmCrmReceivableServiceImplTest.java

+ 43 - 3
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java

@@ -1,5 +1,7 @@
 package cn.iocoder.yudao.module.crm.enums;
 
+import static cn.iocoder.yudao.module.crm.enums.operatelog.CrmParseFunctionNameConstants.GET_CONTRACT_BY_ID;
+
 /**
  * CRM 操作日志枚举
  * 目的:统一管理,也减少 Service 里各种“复杂”字符串
@@ -22,9 +24,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}}】的负责人从【{getAdminUserById{#customer.ownerUserId}}】变更为了【{getAdminUserById{#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 +51,40 @@ 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}}】的负责人从【{getAdminUserById{#contact.ownerUserId}}】变更为了【{getAdminUserById{#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}}】的负责人从【{getAdminUserById{#business.ownerUserId}}】变更为了【{getAdminUserById{#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}}】的负责人从【{getAdminUserById{#contract.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】";
+
 
     // ======================= CRM_PRODUCT 产品 =======================
 
@@ -79,9 +107,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}}】期回款计划";
 
 }

+ 1 - 0
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/operatelog/CrmParseFunctionNameConstants.java

@@ -13,5 +13,6 @@ public interface CrmParseFunctionNameConstants {
     String GET_CUSTOMER_INDUSTRY = "getCustomerIndustry"; // 获取客户行业信息
     String GET_CUSTOMER_LEVEL = "getCustomerLevel"; // 获取客户级别
     String GET_CUSTOMER_SOURCE = "getCustomerSource"; // 获取客户来源
+    String GET_CONTRACT_BY_ID = "getContractById"; // 获取合同信息
 
 }

+ 5 - 10
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<Long> 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<Boolean> transfer(@Valid @RequestBody CrmReceivableTransferReqVO reqVO) {
-        receivableService.transferReceivable(reqVO, getLoginUserId());
-        return success(true);
-    }
-
 }

+ 4 - 9
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<Boolean> transfer(@Valid @RequestBody CrmReceivablePlanTransferReqVO reqVO) {
-        receivablePlanService.transferReceivablePlan(reqVO, getLoginUserId());
-        return success(true);
-    }
-
 }

+ 45 - 20
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) {
@@ -141,18 +180,4 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
                 convertSet(contactBusinessList, CrmContactBusinessDO::getBusinessId));
     }
 
-    @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());
-    }
-
 }

+ 37 - 25
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,27 @@ 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
     @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#id", level = CrmPermissionLevelEnum.READ)
     public CrmContactDO getContact(Long id) {
@@ -191,20 +219,4 @@ public class CrmContactServiceImpl implements CrmContactService {
         return contactMapper.selectPageByCustomerId(pageVO);
     }
 
-    @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 记录转移日志
-    }
-
 }

+ 46 - 19
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,21 +162,6 @@ 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);

+ 3 - 5
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java

@@ -145,10 +145,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 +170,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
 
         // 3. 记录操作日志上下文
         // tips: 因为这里使用的是老的状态所以记录时反着记录,也就是 lockStatus 为 true 那么就是解锁反之为锁定
-        LogRecordContext.putVariable("crmCustomer", customer);
+        LogRecordContext.putVariable("customer", customer);
     }
 
     // ==================== 公海相关操作 ====================

+ 0 - 9
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<CrmReceivablePlanDO> getReceivablePlanPageByCustomerId(CrmReceivablePlanPageReqVO pageReqVO);
 
-    /**
-     * 回款计划转移
-     *
-     * @param reqVO  请求
-     * @param userId 用户编号
-     */
-    void transferReceivablePlan(CrmReceivablePlanTransferReqVO reqVO, Long userId);
-
 }

+ 30 - 24
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 记录转移日志
-    }
-
 }

+ 2 - 10
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<CrmReceivableDO> getReceivablePageByCustomerId(CrmReceivablePageReqVO pageReqVO);
 
-    /**
-     * 回款转移
-     *
-     * @param reqVO  请求
-     * @param userId 用户编号
-     */
-    void transferReceivable(CrmReceivableTransferReqVO reqVO, Long userId);
-
 }

+ 37 - 28
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 记录转移日志
-    }
-
 }

+ 2 - 1
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);
         // 校验记录的属性是否正确