Forráskód Böngészése

Merge branch 'master_20240722' of http://git.dgtis.com/15896567520/oneportal_saas into master_20240722

zhaopeiqing 7 hónapja
szülő
commit
46eb982cb4
69 módosított fájl, 6005 hozzáadás és 6 törlés
  1. 39 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/GeneralStatusEnum.java
  2. 51 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/InfoSourceEnum.java
  3. 1 3
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/stamp/stampinfo/OaStampInfoServiceImpl.java
  4. 29 0
      yudao-module-finance/yudao-module-asset-api/src/main/java/cn/iocoder/yudao/module/asset/enums/AssetReturnStateEnum.java
  5. 54 0
      yudao-module-finance/yudao-module-asset-api/src/main/java/cn/iocoder/yudao/module/asset/enums/AssetStateEnum.java
  6. 49 0
      yudao-module-finance/yudao-module-asset-api/src/main/java/cn/iocoder/yudao/module/asset/enums/AssetStatusEnum.java
  7. 20 0
      yudao-module-finance/yudao-module-asset-api/src/main/java/cn/iocoder/yudao/module/asset/enums/ErrorCodeConstants.java
  8. 155 0
      yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/controller/admin/assetinfo/AssetInfoController.java
  9. 46 0
      yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/controller/admin/assetinfo/vo/AssetInfoPageReqVO.java
  10. 115 0
      yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/controller/admin/assetinfo/vo/AssetInfoRespVO.java
  11. 25 0
      yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/controller/admin/assetinfo/vo/AssetInfoRetireReqVO.java
  12. 58 0
      yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/controller/admin/assetinfo/vo/AssetInfoSaveReqVO.java
  13. 165 0
      yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/controller/admin/assetreceiveinfo/AssetReceiveInfoController.java
  14. 21 0
      yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/controller/admin/assetreceiveinfo/vo/AssetReceiveInfoPageReqVO.java
  15. 93 0
      yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/controller/admin/assetreceiveinfo/vo/AssetReceiveInfoRespVO.java
  16. 29 0
      yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/controller/admin/assetreceiveinfo/vo/AssetReceiveInfoSaveReqVO.java
  17. 25 0
      yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/controller/admin/assetreceiveinfo/vo/AssetReceiveInfoUpdateReqVO.java
  18. 103 0
      yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/dal/dataobject/assetinfo/AssetInfoDO.java
  19. 87 0
      yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/dal/dataobject/assetreceiveinfo/AssetReceiveInfoDO.java
  20. 50 0
      yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/dal/mysql/assetinfo/AssetInfoMapper.java
  21. 24 0
      yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/dal/mysql/assetreceiveinfo/AssetReceiveInfoMapper.java
  22. 27 0
      yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/framework/config/AssetWebConfiguration.java
  23. 70 0
      yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/service/assetinfo/AssetInfoService.java
  24. 172 0
      yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/service/assetinfo/AssetInfoServiceImpl.java
  25. 56 0
      yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/service/assetreceiveinfo/AssetReceiveInfoService.java
  26. 180 0
      yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/service/assetreceiveinfo/AssetReceiveInfoServiceImpl.java
  27. 124 0
      yudao-module-finance/yudao-module-asset-biz/src/main/resources/mapper/assetinfo/AssetInfoMapper.xml
  28. 12 0
      yudao-module-finance/yudao-module-asset-biz/src/main/resources/mapper/assetreceiveinfo/AssetReceiveInfoMapper.xml
  29. 162 0
      yudao-module-finance/yudao-module-asset-biz/src/test/java/cn/iocoder/yudao/module/asset/service/assetinfo/AssetInfoServiceImplTest.java
  30. 162 0
      yudao-module-finance/yudao-module-asset-biz/src/test/java/cn/iocoder/yudao/module/asset/service/assetreceiveinfo/AssetReceiveInfoServiceImplTest.java
  31. 1 1
      yudao-module-finance/yudao-module-cash-biz/src/main/java/cn/iocoder/yudao/module/cash/service/paymentinfo/PaymentInfoServiceImpl.java
  32. 1 1
      yudao-module-finance/yudao-module-cash-biz/src/main/java/cn/iocoder/yudao/module/cash/service/refundinfo/RefundInfoServiceImpl.java
  33. 35 0
      yudao-module-finance/yudao-module-contract-api/src/main/java/cn/iocoder/yudao/module/contract/enums/ContractStatusEnum.java
  34. 18 0
      yudao-module-finance/yudao-module-contract-api/src/main/java/cn/iocoder/yudao/module/contract/enums/ErrorCodeConstants.java
  35. 289 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/customercontract/CustomerContractController.java
  36. 21 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/customercontract/vo/CustomerContractCloseReqVO.java
  37. 53 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/customercontract/vo/CustomerContractPageReqVO.java
  38. 137 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/customercontract/vo/CustomerContractRespVO.java
  39. 66 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/customercontract/vo/CustomerContractSaveReqVO.java
  40. 21 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/customercontract/vo/CustomerContractStatusReqVO.java
  41. 25 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/customercontract/vo/CustomerContractTerminatedReqVO.java
  42. 287 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/suppliercontract/SupplierContractController.java
  43. 21 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/suppliercontract/vo/SupplierContractCloseReqVO.java
  44. 52 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/suppliercontract/vo/SupplierContractPageReqVO.java
  45. 136 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/suppliercontract/vo/SupplierContractRespVO.java
  46. 64 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/suppliercontract/vo/SupplierContractSaveReqVO.java
  47. 21 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/suppliercontract/vo/SupplierContractStatusReqVO.java
  48. 25 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/suppliercontract/vo/SupplierContractTerminatedReqVO.java
  49. 108 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/dal/dataobject/customercontract/CustomerContractDO.java
  50. 108 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/dal/dataobject/customercontract/CustomerContractHistoryDO.java
  51. 108 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/dal/dataobject/suppliercontract/SupplierContractDO.java
  52. 108 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/dal/dataobject/suppliercontract/SupplierContractHistoryDO.java
  53. 35 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/dal/mysql/customercontract/CustomerContractHistoryMapper.java
  54. 62 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/dal/mysql/customercontract/CustomerContractMapper.java
  55. 34 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/dal/mysql/suppliercontract/SupplierContractHistoryMapper.java
  56. 60 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/dal/mysql/suppliercontract/SupplierContractMapper.java
  57. 29 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/framework/config/ContractWebConfiguration.java
  58. 160 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/service/customercontract/CustomerContractService.java
  59. 322 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/service/customercontract/CustomerContractServiceImpl.java
  60. 160 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/service/suppliercontract/SupplierContractService.java
  61. 318 0
      yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/service/suppliercontract/SupplierContractServiceImpl.java
  62. 91 0
      yudao-module-finance/yudao-module-contract-biz/src/main/resources/mapper/customercontract/CustomerContractHistoryMapper.xml
  63. 161 0
      yudao-module-finance/yudao-module-contract-biz/src/main/resources/mapper/customercontract/CustomerContractMapper.xml
  64. 91 0
      yudao-module-finance/yudao-module-contract-biz/src/main/resources/mapper/suppliercontract/SupplierContractHistoryMapper.xml
  65. 160 0
      yudao-module-finance/yudao-module-contract-biz/src/main/resources/mapper/suppliercontract/SupplierContractMapper.xml
  66. 206 0
      yudao-module-finance/yudao-module-contract-biz/src/test/java/cn/iocoder/yudao/module/contract/service/customercontract/CustomerContractServiceImplTest.java
  67. 202 0
      yudao-module-finance/yudao-module-contract-biz/src/test/java/cn/iocoder/yudao/module/contract/service/suppliercontract/SupplierContractServiceImplTest.java
  68. 1 1
      yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/service/expenseinfo/ExpenseInfoServiceImpl.java
  69. 4 0
      yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/api/info/EmployeeApiImpl.java

+ 39 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/GeneralStatusEnum.java

@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.framework.common.enums;
+
+/**
+ * 通用状态枚举 0否 1是
+ */
+public enum GeneralStatusEnum {
+    /**
+     * 0否
+     */
+    NO(0, "否"),
+    /**
+     * 1是
+     */
+    YES(1, "是");
+
+    private final Integer status;
+    private final String statusDesc;
+
+    GeneralStatusEnum(Integer status, String statusDesc) {
+        this.status = status;
+        this.statusDesc = statusDesc;
+    }
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public String getName() {
+        return statusDesc;
+    }
+
+    public static boolean isNo(Integer status) {
+        return NO.getStatus().equals(status);
+    }
+
+    public static boolean isYes(Integer status) {
+        return YES.getStatus().equals(status);
+    }
+}

+ 51 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/InfoSourceEnum.java

@@ -0,0 +1,51 @@
+package cn.iocoder.yudao.framework.common.enums;
+
+/**
+ * 信息来源枚举类
+ * 用于标识信息的来源方式,如流程生成或手动添加
+ */
+public enum InfoSourceEnum {
+    /**
+     * 流程生成的信息来源
+     */
+    FLOW("flow", "流程生成"),
+    /**
+     * 手动添加的信息来源
+     */
+    MANUAL("manual", "手动添加"),
+    ;
+
+    // 来源标识符
+    private final String source;
+    // 来源描述
+    private final String desc;
+
+    /**
+     * 枚举构造函数
+     *
+     * @param source 来源标识符
+     * @param desc 来源描述
+     */
+    InfoSourceEnum(String source, String desc) {
+        this.source = source;
+        this.desc = desc;
+    }
+
+    /**
+     * 获取来源标识符
+     *
+     * @return 来源标识符
+     */
+    public String getSource() {
+        return source;
+    }
+
+    /**
+     * 获取来源描述
+     *
+     * @return 来源描述
+     */
+    public String getDesc() {
+        return desc;
+    }
+}

+ 1 - 3
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/stamp/stampinfo/OaStampInfoServiceImpl.java

@@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.framework.security.core.LoginUser;
 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
-import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
 import cn.iocoder.yudao.module.bpm.controller.admin.stamp.stampinfo.vo.OaStampInfoPageReqVO;
 import cn.iocoder.yudao.module.bpm.controller.admin.stamp.stampinfo.vo.OaStampInfoRespVO;
 import cn.iocoder.yudao.module.bpm.controller.admin.stamp.stampinfo.vo.OaStampInfoSaveReqVO;
@@ -15,7 +14,6 @@ import cn.iocoder.yudao.module.bpm.dal.mysql.stamp.stampinfo.OaStampInfoMapper;
 import cn.iocoder.yudao.module.employee.api.EmployeeApi;
 import cn.iocoder.yudao.module.employee.api.dto.EmployeeRespDTO;
 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
-import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
@@ -133,7 +131,7 @@ public class OaStampInfoServiceImpl implements OaStampInfoService {
 
     @Override
     public PageResult<OaStampInfoRespVO> getOaStampInfoPage(OaStampInfoPageReqVO pageReqVO) {
-        pageReqVO.setPageNo(pageReqVO.getPageNo() - 1);
+        pageReqVO.setPageNo((pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize());
 
         long pageCount = oaStampInfoMapper.selectPageCount(pageReqVO);
         List<OaStampInfoRespVO> pageList = oaStampInfoMapper.selectPageList(pageReqVO);

+ 29 - 0
yudao-module-finance/yudao-module-asset-api/src/main/java/cn/iocoder/yudao/module/asset/enums/AssetReturnStateEnum.java

@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.module.asset.enums;
+
+public enum AssetReturnStateEnum {
+    /**
+     * 0未归还
+     */
+    NOT_RETURNED(0, "未归还"),
+    /**
+     * 1已归还
+     */
+    RETURNED(1, "已归还"),
+    ;
+
+    private final Integer state;
+    private final String desc;
+
+    AssetReturnStateEnum(Integer state, String desc) {
+        this.state = state;
+        this.desc = desc;
+    }
+
+    public Integer getState() {
+        return state;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+}

+ 54 - 0
yudao-module-finance/yudao-module-asset-api/src/main/java/cn/iocoder/yudao/module/asset/enums/AssetStateEnum.java

@@ -0,0 +1,54 @@
+package cn.iocoder.yudao.module.asset.enums;
+
+/**
+ * 资产状态枚举
+ * 用于标识资产的不同状态,每种状态都有一个相应的代码和描述
+ */
+public enum AssetStateEnum {
+    /**
+     * 可用状态的资产
+     */
+    AVAILABLE("0", "可用"),
+    /**
+     * 已被占用的资产
+     */
+    OCCUPIED("1", "占用"),
+    /**
+     * 已报废的资产
+     */
+    RETIRED("2", "已报废");
+
+    // 状态代码,用于系统内部标识不同的资产状态
+    private final String state;
+    // 状态描述,用于用户界面或其他需要人类可读信息的场景
+    private final String desc;
+
+    /**
+     * 枚举构造函数,初始化状态代码和描述
+     *
+     * @param state 状态代码
+     * @param desc  状态描述
+     */
+    AssetStateEnum(String state, String desc) {
+        this.state = state;
+        this.desc = desc;
+    }
+
+    /**
+     * 获取状态代码
+     *
+     * @return 状态代码
+     */
+    public String getState() {
+        return state;
+    }
+
+    /**
+     * 获取状态描述
+     *
+     * @return 状态描述
+     */
+    public String getDesc() {
+        return desc;
+    }
+}

+ 49 - 0
yudao-module-finance/yudao-module-asset-api/src/main/java/cn/iocoder/yudao/module/asset/enums/AssetStatusEnum.java

@@ -0,0 +1,49 @@
+package cn.iocoder.yudao.module.asset.enums;
+
+/**
+ * 资产信息单据状态枚举类
+ */
+public enum AssetStatusEnum {
+    /**
+     * 资产状态已完成
+     */
+    COMPLETED("0", "已完成"),
+    /**
+     * 资产状态已作废
+     */
+    ABANDONED("1", "已作废");
+
+    // 状态码,用于系统中存储和传输资产状态的标识
+    private final String status;
+    // 状态描述,用于展示给用户看的状态文字
+    private final String desc;
+
+    /**
+     * 枚举构造器,初始化状态码和状态描述
+     *
+     * @param status 状态码
+     * @param desc   状态描述
+     */
+    AssetStatusEnum(String status, String desc) {
+        this.status = status;
+        this.desc = desc;
+    }
+
+    /**
+     * 获取状态码
+     *
+     * @return 状态码
+     */
+    public String getStatus() {
+        return status;
+    }
+
+    /**
+     * 获取状态描述
+     *
+     * @return 状态描述
+     */
+    public String getDesc() {
+        return desc;
+    }
+}

+ 20 - 0
yudao-module-finance/yudao-module-asset-api/src/main/java/cn/iocoder/yudao/module/asset/enums/ErrorCodeConstants.java

@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.asset.enums;
+
+import cn.iocoder.yudao.framework.common.exception.ErrorCode;
+
+public interface ErrorCodeConstants {
+
+    // ========== 固定资产信息 1_051_001_001 ==========
+    ErrorCode INFO_NOT_EXISTS = new ErrorCode(1_051_001_001, "固定资产信息不存在");
+    ErrorCode OCCUPIED_ASSET_NOT_ALLOWED_DELETE = new ErrorCode(1_051_001_002, "该资产已被占用,不允许删除");
+    ErrorCode ASSET_INFO_NOT_AVAILABLE = new ErrorCode(1_051_001_003, "该资产不是可用状态,无法领用");
+    ErrorCode ASSET_INFO_NOT_OCCUPIED = new ErrorCode(1_051_001_004, "该资产不是占用状态,无需归还");
+
+    // ========== 固定资产领用信息 1_051_002_001 ==========
+    ErrorCode RECEIVE_INFO_NOT_EXISTS = new ErrorCode(1_051_002_001, "固定资产领用信息不存在");
+    ErrorCode ASSET_RECEIVE_EMPLOYEE_NOT_NULL = new ErrorCode(1_051_002_002, "领用人不能为空");
+    ErrorCode ASSET_RECEIVE_DATE_NOT_BLANK = new ErrorCode(1_051_002_003, "领用日期不能为空");
+    ErrorCode ASSET_RECEIVE_REASON_NOT_BLANK = new ErrorCode(1_051_002_004, "领用原因不能为空");
+    ErrorCode ASSET_RETURN_DATE_NOT_BLANK = new ErrorCode(1_051_002_005, "归还日期不能为空");
+    ErrorCode ASSET_RETURN_REASON_NOT_BLANK = new ErrorCode(1_051_002_006, "归还原因不能为空");
+}

+ 155 - 0
yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/controller/admin/assetinfo/AssetInfoController.java

@@ -0,0 +1,155 @@
+package cn.iocoder.yudao.module.asset.controller.admin.assetinfo;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+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.module.asset.controller.admin.assetinfo.vo.AssetInfoPageReqVO;
+import cn.iocoder.yudao.module.asset.controller.admin.assetinfo.vo.AssetInfoRespVO;
+import cn.iocoder.yudao.module.asset.controller.admin.assetinfo.vo.AssetInfoRetireReqVO;
+import cn.iocoder.yudao.module.asset.controller.admin.assetinfo.vo.AssetInfoSaveReqVO;
+import cn.iocoder.yudao.module.asset.dal.dataobject.assetinfo.AssetInfoDO;
+import cn.iocoder.yudao.module.asset.enums.AssetStateEnum;
+import cn.iocoder.yudao.module.asset.enums.AssetStatusEnum;
+import cn.iocoder.yudao.module.asset.service.assetinfo.AssetInfoService;
+import cn.iocoder.yudao.module.employee.api.EmployeeApi;
+import cn.iocoder.yudao.module.employee.api.dto.EmployeeRespDTO;
+import cn.iocoder.yudao.module.infra.api.file.FileApi;
+import cn.iocoder.yudao.module.infra.api.file.dto.FileDTO;
+import cn.iocoder.yudao.module.system.api.dept.DeptApi;
+import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springdoc.api.annotations.ParameterObject;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 固定资产信息")
+@RestController
+@RequestMapping("/finance/asset/info")
+@Validated
+public class AssetInfoController {
+
+    @Resource
+    private AssetInfoService infoService;
+
+    @Resource
+    private EmployeeApi employeeApi;
+
+    @Resource
+    private FileApi fileApi;
+
+    @Resource
+    private DeptApi deptApi;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建固定资产信息")
+    @ApiOperationSupport(order = 1)
+    // @PreAuthorize("@ss.hasPermission('asset:info:create')")
+    public CommonResult<Long> createInfo(@Valid @RequestBody AssetInfoSaveReqVO createReqVO) {
+        return success(infoService.createInfo(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新固定资产信息")
+    @ApiOperationSupport(order = 2)
+    // @PreAuthorize("@ss.hasPermission('asset:info:update')")
+    public CommonResult<Boolean> updateInfo(@Valid @RequestBody AssetInfoSaveReqVO updateReqVO) {
+        infoService.updateInfo(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除固定资产信息")
+    @ApiOperationSupport(order = 3)
+    @Parameter(name = "id", description = "编号", required = true)
+    // @PreAuthorize("@ss.hasPermission('asset:info:delete')")
+    public CommonResult<Boolean> deleteInfo(@RequestParam("id") Long id) {
+        infoService.deleteInfo(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得固定资产信息")
+    @ApiOperationSupport(order = 4)
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    // @PreAuthorize("@ss.hasPermission('asset:info:query')")
+    public CommonResult<AssetInfoRespVO> getInfo(@RequestParam("id") Long id) {
+        AssetInfoDO info = infoService.getInfo(id);
+        AssetInfoRespVO assetInfoRespVO = BeanUtils.toBean(info, AssetInfoRespVO.class);
+        // 归属部门名称
+        DeptRespDTO dept = deptApi.getDept(info.getAssetDeptId());
+        if (Objects.nonNull(dept)) {
+            assetInfoRespVO.setAssetDeptName(dept.getName());
+        }
+        // 资产负责人名称
+        EmployeeRespDTO employee = employeeApi.getEmployeeById(info.getAssetManagerEmployeeId());
+        if (Objects.nonNull(employee)) {
+            assetInfoRespVO.setAssetManagerEmployeeName(employee.getName());
+        }
+        // 资产状态
+        Map<String, String> assetStateMap = Arrays.stream(AssetStateEnum.values())
+                .collect(Collectors.toMap(AssetStateEnum::getState, AssetStateEnum::getDesc));
+        assetInfoRespVO.setAssetStateDesc(assetStateMap.getOrDefault(assetInfoRespVO.getAssetState(), "未知"));
+        // 单据状态
+        Map<String, String> assetStatusMap = Arrays.stream(AssetStatusEnum.values())
+                .collect(Collectors.toMap(AssetStatusEnum::getStatus, AssetStatusEnum::getDesc));
+        assetInfoRespVO.setStatusDesc(assetStatusMap.getOrDefault(assetInfoRespVO.getStatus(), "未知"));
+        // 附件
+        List<FileDTO> fileDTOListByBiz = fileApi.getFileDTOListByBiz(info.getAssetInfoUuid());
+        assetInfoRespVO.setFileList(fileDTOListByBiz);
+
+        return success(assetInfoRespVO);
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得固定资产信息分页")
+    @ApiOperationSupport(order = 5)
+    // @PreAuthorize("@ss.hasPermission('asset:info:query')")
+    public CommonResult<PageResult<AssetInfoRespVO>> getInfoPage(@Valid @ParameterObject AssetInfoPageReqVO pageReqVO) {
+        PageResult<AssetInfoRespVO> pageResult = infoService.getInfoPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, AssetInfoRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出固定资产信息 Excel")
+    @ApiOperationSupport(order = 6)
+    // @PreAuthorize("@ss.hasPermission('asset:info:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportInfoExcel(@Valid @ParameterObject AssetInfoPageReqVO pageReqVO,
+                                HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<AssetInfoRespVO> list = infoService.getInfoPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "固定资产信息.xls", "数据", AssetInfoRespVO.class,
+                list);
+    }
+
+    @PostMapping("/retire")
+    @Operation(summary = "报废固定资产信息")
+    @ApiOperationSupport(order = 7)
+    // @PreAuthorize("@ss.hasPermission('asset:info:delete')")
+    public CommonResult<Boolean> retireInfo(@Valid @RequestBody AssetInfoRetireReqVO retireReqVO) {
+        infoService.retireInfo(retireReqVO);
+        return success(true);
+    }
+
+
+}

+ 46 - 0
yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/controller/admin/assetinfo/vo/AssetInfoPageReqVO.java

@@ -0,0 +1,46 @@
+package cn.iocoder.yudao.module.asset.controller.admin.assetinfo.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 static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
+
+@Schema(description = "管理后台 - 固定资产信息分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class AssetInfoPageReqVO extends PageParam {
+
+    @Schema(description = "资产编号:年月日+uuid")
+    private String assetInfoUuid;
+
+    @Schema(description = "资产名称")
+    private String name;
+
+    @Schema(description = "资产型号")
+    private String typeNumber;
+
+    @Schema(description = "资产序列号")
+    private String serialNumber;
+
+    @Schema(description = "资产化日期", example = "2024-08-08,2024-08-08")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
+    private String[] capitalizationDate;
+
+    @Schema(description = "折旧年限(大于0的自然数)")
+    private Integer depreciationYear;
+
+    @Schema(description = "资产状态:0可用 1占用 2报废")
+    private String assetState;
+
+    @Schema(description = "领用人名称")
+    private String receiveEmployeeName;
+
+    @Schema(description = "资产归属部门")
+    private Long assetDeptId;
+
+}

+ 115 - 0
yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/controller/admin/assetinfo/vo/AssetInfoRespVO.java

@@ -0,0 +1,115 @@
+package cn.iocoder.yudao.module.asset.controller.admin.assetinfo.vo;
+
+import cn.iocoder.yudao.module.infra.api.file.dto.FileDTO;
+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;
+import java.util.List;
+
+@Schema(description = "管理后台 - 固定资产信息 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class AssetInfoRespVO {
+
+    @Schema(description = "资产信息主键自增id")
+    @ExcelProperty("资产信息主键自增id")
+    private Long id;
+
+    @Schema(description = "资产编号:年月日+uuid")
+    @ExcelProperty("资产编号:年月日+uuid")
+    private String assetInfoUuid;
+
+    @Schema(description = "资产名称")
+    @ExcelProperty("资产名称")
+    private String name;
+
+    @Schema(description = "资产型号")
+    @ExcelProperty("资产型号")
+    private String typeNumber;
+
+    @Schema(description = "资产序列号")
+    @ExcelProperty("资产序列号")
+    private String serialNumber;
+
+    @Schema(description = "购买日期")
+    @ExcelProperty("购买日期")
+    private String purchaseDate;
+
+    @Schema(description = "资产化日期")
+    @ExcelProperty("资产化日期")
+    private String capitalizationDate;
+
+    @Schema(description = "折旧年限(大于0的自然数)")
+    @ExcelProperty("折旧年限(大于0的自然数)")
+    private Integer depreciationYear;
+
+    @Schema(description = "资产状态:0可用 1占用 2报废")
+    @ExcelProperty("资产状态:0可用 1占用 2报废")
+    private String assetState;
+
+    @Schema(description = "资产状态描述:0可用 1占用 2报废")
+    @ExcelProperty("资产状态描述:0可用 1占用 2报废")
+    private String assetStateDesc;
+
+    @Schema(description = "领用人id")
+    @ExcelProperty("领用人id")
+    private Long receiveEmployeeId;
+
+    @Schema(description = "领用人姓名")
+    @ExcelProperty("领用人姓名")
+    private Long receiveEmployeeName;
+
+    @Schema(description = "领用信息表主键id")
+    @ExcelProperty("领用信息表主键id")
+    private Long receiveInfoId;
+
+    @Schema(description = "资产归属部门")
+    @ExcelProperty("资产归属部门")
+    private Long assetDeptId;
+
+    @Schema(description = "资产归属部门名称")
+    @ExcelProperty("资产归属部门名称")
+    private String assetDeptName;
+
+    @Schema(description = "资产归属地")
+    @ExcelProperty("资产归属地")
+    private String assetPlace;
+
+    @Schema(description = "资产管理负责人")
+    @ExcelProperty("资产管理负责人")
+    private Long assetManagerEmployeeId;
+
+    @Schema(description = "资产管理负责人名称")
+    @ExcelProperty("资产管理负责人名称")
+    private String assetManagerEmployeeName;
+
+    @Schema(description = "报废日期")
+    @ExcelProperty("报废日期")
+    private String retirementDate;
+
+    @Schema(description = "报废原因")
+    @ExcelProperty("报废原因")
+    private String retirementReason;
+
+    @Schema(description = "单据状态:0:已完成,1:作废")
+    @ExcelProperty("单据状态:0:已完成,1:作废")
+    private String status;
+
+    @Schema(description = "单据状态名称:0:已完成,1:作废")
+    @ExcelProperty("单据状态名称:0:已完成,1:作废")
+    private String statusDesc;
+
+    @Schema(description = "备注")
+    @ExcelProperty("备注")
+    private String remarks;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+    @Schema(description = "附件列表")
+    private List<FileDTO> fileList;
+}

+ 25 - 0
yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/controller/admin/assetinfo/vo/AssetInfoRetireReqVO.java

@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.asset.controller.admin.assetinfo.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 固定资产信息报废 Request VO")
+@Data
+public class AssetInfoRetireReqVO {
+
+    @Schema(description = "资产信息主键自增id",requiredMode = Schema.RequiredMode.REQUIRED,example = "1")
+    @NotNull(message = "资产信息主键自增id不能为空")
+    private Long id;
+
+    @Schema(description = "报废日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-08-08")
+    @NotBlank(message = "报废日期不能为空")
+    private String retirementDate;
+
+    @Schema(description = "报废原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "报废原因不能为空")
+    @NotBlank(message = "报废原因不能为空")
+    private String retirementReason;
+
+}

+ 58 - 0
yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/controller/admin/assetinfo/vo/AssetInfoSaveReqVO.java

@@ -0,0 +1,58 @@
+package cn.iocoder.yudao.module.asset.controller.admin.assetinfo.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+@Schema(description = "管理后台 - 固定资产信息新增/修改 Request VO")
+@Data
+public class AssetInfoSaveReqVO {
+
+    @Schema(description = "资产信息主键自增id", example = "1")
+    private Long id;
+
+    @Schema(description = "资产名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "资产名称不能为空")
+    @NotBlank(message = "资产名称不能为空")
+    private String name;
+
+    @Schema(description = "资产型号", example = "资产型号可以为空")
+    private String typeNumber;
+
+    @Schema(description = "资产序列号", example = "资产序列号可以为空")
+    private String serialNumber;
+
+    @Schema(description = "购买日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-08-08")
+    @NotBlank(message = "购买日期不能为空")
+    private String purchaseDate;
+
+    @Schema(description = "资产化日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-08-09")
+    @NotBlank(message = "资产化日期不能为空")
+    private String capitalizationDate;
+
+    @Schema(description = "折旧年限(大于0的自然数)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @NotNull(message = "折旧年限不能为空")
+    @Min(value = 1, message = "折旧年限必须大于0")
+    private Integer depreciationYear;
+
+    @Schema(description = "资产归属部门", requiredMode = Schema.RequiredMode.REQUIRED, example = "103")
+    @NotNull(message = "资产归属部门不能为空")
+    private Long assetDeptId;
+
+    @Schema(description = "资产归属地", example = "资产归属地可以为空")
+    private String assetPlace;
+
+    @Schema(description = "资产管理负责人", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @NotNull(message = "资产管理负责人不能为空")
+    private Long assetManagerEmployeeId;
+
+    @Schema(description = "备注", example = "备注可以为空")
+    private String remarks;
+
+    @Schema(description = "附件主键id", example = "[]")
+    private List<Long> fileIdList;
+
+}

+ 165 - 0
yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/controller/admin/assetreceiveinfo/AssetReceiveInfoController.java

@@ -0,0 +1,165 @@
+package cn.iocoder.yudao.module.asset.controller.admin.assetreceiveinfo;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+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.collection.CollectionUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.yudao.module.asset.controller.admin.assetreceiveinfo.vo.AssetReceiveInfoPageReqVO;
+import cn.iocoder.yudao.module.asset.controller.admin.assetreceiveinfo.vo.AssetReceiveInfoRespVO;
+import cn.iocoder.yudao.module.asset.controller.admin.assetreceiveinfo.vo.AssetReceiveInfoSaveReqVO;
+import cn.iocoder.yudao.module.asset.controller.admin.assetreceiveinfo.vo.AssetReceiveInfoUpdateReqVO;
+import cn.iocoder.yudao.module.asset.dal.dataobject.assetreceiveinfo.AssetReceiveInfoDO;
+import cn.iocoder.yudao.module.asset.enums.AssetReturnStateEnum;
+import cn.iocoder.yudao.module.asset.service.assetreceiveinfo.AssetReceiveInfoService;
+import cn.iocoder.yudao.module.employee.api.EmployeeApi;
+import cn.iocoder.yudao.module.employee.api.dto.EmployeeRespDTO;
+import cn.iocoder.yudao.module.system.api.dept.DeptApi;
+import cn.iocoder.yudao.module.system.api.dept.PostApi;
+import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
+import cn.iocoder.yudao.module.system.api.dept.dto.PostRespDTO;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springdoc.api.annotations.ParameterObject;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 固定资产领用、归还信息")
+@RestController
+@RequestMapping("/finance/asset/receive-info")
+@Validated
+public class AssetReceiveInfoController {
+
+    @Resource
+    private AssetReceiveInfoService receiveInfoService;
+
+    @Resource
+    private EmployeeApi employeeApi;
+
+    @Resource
+    private DeptApi deptApi;
+
+    @Resource
+    private PostApi postApi;
+
+    @PostMapping("/create")
+    @Operation(summary = "领用固定资产")
+    @ApiOperationSupport(order = 1)
+    // @PreAuthorize("@ss.hasPermission('asset:receive-info:create')")
+    public CommonResult<Long> createReceiveInfo(@Valid @RequestBody AssetReceiveInfoSaveReqVO createReqVO) {
+        return success(receiveInfoService.createReceiveInfo(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "归还固定资产")
+    @ApiOperationSupport(order = 2)
+    // @PreAuthorize("@ss.hasPermission('asset:receive-info:update')")
+    public CommonResult<Boolean> updateReceiveInfo(@Valid @RequestBody AssetReceiveInfoUpdateReqVO updateReqVO) {
+        receiveInfoService.updateReceiveInfo(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除固定资产领用信息")
+    @ApiOperationSupport(order = 4)
+    @Parameter(name = "id", description = "编号", required = true)
+    // @PreAuthorize("@ss.hasPermission('asset:receive-info:delete')")
+    public CommonResult<Boolean> deleteReceiveInfo(@RequestParam("id") Long id) {
+        receiveInfoService.deleteReceiveInfo(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得固定资产领用信息")
+    @ApiOperationSupport(order = 5)
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    // @PreAuthorize("@ss.hasPermission('asset:receive-info:query')")
+    public CommonResult<AssetReceiveInfoRespVO> getReceiveInfo(@RequestParam("id") Long id) {
+        AssetReceiveInfoDO receiveInfo = receiveInfoService.getReceiveInfo(id);
+        return success(BeanUtils.toBean(receiveInfo, AssetReceiveInfoRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得固定资产流转分页信息")
+    @ApiOperationSupport(order = 3)
+    // @PreAuthorize("@ss.hasPermission('asset:receive-info:query')")
+    public CommonResult<PageResult<AssetReceiveInfoRespVO>> getReceiveInfoPage(@Valid @ParameterObject AssetReceiveInfoPageReqVO pageReqVO) {
+        PageResult<AssetReceiveInfoDO> pageResult = receiveInfoService.getReceiveInfoPage(pageReqVO);
+        PageResult<AssetReceiveInfoRespVO> voPageResult = BeanUtils.toBean(pageResult, AssetReceiveInfoRespVO.class);
+        List<AssetReceiveInfoRespVO> list = voPageResult.getList();
+
+        // 领用人信息
+        Set<Long> employeeIdSet = list.stream().map(AssetReceiveInfoRespVO::getEmployeeId).collect(Collectors.toSet());
+        List<EmployeeRespDTO> employeeRespDTOList = employeeApi.getEmployeeListByIds(employeeIdSet);
+        Map<Long, EmployeeRespDTO> employeeMap = CollectionUtils.convertMap(employeeRespDTOList, EmployeeRespDTO::getId);
+        // 领用人部门信息
+        Set<Long> deptIdSet = list.stream().map(AssetReceiveInfoRespVO::getDeptId).collect(Collectors.toSet());
+        List<DeptRespDTO> deptList = deptApi.getDeptList(deptIdSet);
+        Map<Long, DeptRespDTO> deptMap = CollectionUtils.convertMap(deptList, DeptRespDTO::getId);
+        // 领用人职位信息
+        Set<Long> postIdSet = list.stream().map(AssetReceiveInfoRespVO::getPostId).collect(Collectors.toSet());
+        List<PostRespDTO> postList = postApi.getPostList(postIdSet);
+        Map<Long, PostRespDTO> postMap = CollectionUtils.convertMap(postList, PostRespDTO::getId);
+        // 操作人
+        Set<Long> updaterIdSet = list.stream().map(AssetReceiveInfoRespVO::getUpdater).collect(Collectors.toSet());
+        List<EmployeeRespDTO> updaterList = employeeApi.getEmployeeListByIds(updaterIdSet);
+        Map<Long, EmployeeRespDTO> updaterMap = CollectionUtils.convertMap(updaterList, EmployeeRespDTO::getId);
+        // 是否归还
+        Map<Integer, String> returnStateMap = Arrays.stream(AssetReturnStateEnum.values()).collect(Collectors.toMap(AssetReturnStateEnum::getState, AssetReturnStateEnum::getDesc));
+
+        for (AssetReceiveInfoRespVO assetReceiveInfoRespVO : list) {
+            EmployeeRespDTO employeeRespDTO = employeeMap.get(assetReceiveInfoRespVO.getEmployeeId());
+            if (employeeRespDTO != null) {
+                assetReceiveInfoRespVO.setEmployeeName(employeeRespDTO.getName());
+                assetReceiveInfoRespVO.setEmployeePhone(employeeRespDTO.getPhone());
+            }
+            DeptRespDTO deptRespDTO = deptMap.get(assetReceiveInfoRespVO.getDeptId());
+            if (deptRespDTO != null) {
+                assetReceiveInfoRespVO.setDeptName(deptRespDTO.getName());
+            }
+            PostRespDTO postRespDTO = postMap.get(assetReceiveInfoRespVO.getPostId());
+            if (postRespDTO != null) {
+                assetReceiveInfoRespVO.setPosition(postRespDTO.getName());
+            }
+            EmployeeRespDTO updaterRespDTO = updaterMap.get(assetReceiveInfoRespVO.getUpdater());
+            if (updaterRespDTO != null) {
+                assetReceiveInfoRespVO.setOperatorName(updaterRespDTO.getName());
+            }
+            String returnStateDesc = returnStateMap.getOrDefault(assetReceiveInfoRespVO.getReturned(), "未知");
+            assetReceiveInfoRespVO.setReturnedDesc(returnStateDesc);
+        }
+        return success(voPageResult);
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出固定资产领用信息 Excel")
+    @ApiOperationSupport(order = 6)
+    // @PreAuthorize("@ss.hasPermission('asset:receive-info:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportReceiveInfoExcel(@Valid AssetReceiveInfoPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<AssetReceiveInfoDO> list = receiveInfoService.getReceiveInfoPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "固定资产领用信息.xls", "数据", AssetReceiveInfoRespVO.class,
+                        BeanUtils.toBean(list, AssetReceiveInfoRespVO.class));
+    }
+
+}

+ 21 - 0
yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/controller/admin/assetreceiveinfo/vo/AssetReceiveInfoPageReqVO.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.asset.controller.admin.assetreceiveinfo.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 javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 固定资产领用信息分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class AssetReceiveInfoPageReqVO extends PageParam {
+
+    @Schema(description = "固定资产信息表主键id")
+    @NotNull(message = "领用资产不能为空")
+    private Long assetInfoId;
+
+}

+ 93 - 0
yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/controller/admin/assetreceiveinfo/vo/AssetReceiveInfoRespVO.java

@@ -0,0 +1,93 @@
+package cn.iocoder.yudao.module.asset.controller.admin.assetreceiveinfo.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 固定资产领用信息 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class AssetReceiveInfoRespVO {
+
+    @Schema(description = "主键自增id")
+    @ExcelProperty("主键自增id")
+    private Long id;
+
+    @Schema(description = "领用编号uuid")
+    @ExcelProperty("领用编号uuid")
+    private String receiveInfoUuid;
+
+    @Schema(description = "领用人id")
+    @ExcelProperty("领用人id")
+    private Long employeeId;
+
+    @Schema(description = "领用人姓名")
+    @ExcelProperty("领用人姓名")
+    private String employeeName;
+
+    @Schema(description = "领用人手机号")
+    @ExcelProperty("领用人手机号")
+    private String employeePhone;
+
+    @Schema(description = "部门id")
+    @ExcelProperty("部门id")
+    private Long deptId;
+
+    @Schema(description = "部门名称")
+    @ExcelProperty("部门名称")
+    private String deptName;
+
+    @Schema(description = "职位id")
+    @ExcelProperty("职位id")
+    private Long postId;
+
+    @Schema(description = "职位名称")
+    @ExcelProperty("职位名称")
+    private String position;
+
+    @Schema(description = "固定资产信息表主键id")
+    @ExcelProperty("固定资产信息表主键id")
+    private Long assetInfoId;
+
+    @Schema(description = "固定资产名称")
+    @ExcelProperty("固定资产名称")
+    private String assetInfoName;
+
+    @Schema(description = "领用日期")
+    @ExcelProperty("领用日期")
+    private String receiveDate;
+
+    @Schema(description = "领用原因")
+    @ExcelProperty("领用原因")
+    private String reason;
+
+    @Schema(description = "是否归还:0未归还,1已归还")
+    @ExcelProperty("是否归还:0未归还,1已归还")
+    private Integer returned;
+
+    @Schema(description = "是否归还描述:0未归还,1已归还")
+    @ExcelProperty("是否归还描述:0未归还,1已归还")
+    private String returnedDesc;
+
+    @Schema(description = "归还日期")
+    @ExcelProperty("归还日期")
+    private String returnDate;
+
+    @Schema(description = "归还原因")
+    @ExcelProperty("归还原因")
+    private String returnReason;
+
+    @Schema(description = "创建者")
+    @ExcelProperty("创建者")
+    private Long creator;
+
+    @Schema(description = "更新者")
+    @ExcelProperty("更新者")
+    private Long updater;
+
+    @Schema(description = "操作人姓名")
+    @ExcelProperty("操作人姓名")
+    private String operatorName;
+
+}

+ 29 - 0
yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/controller/admin/assetreceiveinfo/vo/AssetReceiveInfoSaveReqVO.java

@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.module.asset.controller.admin.assetreceiveinfo.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 固定资产领用信息新增/修改 Request VO")
+@Data
+public class AssetReceiveInfoSaveReqVO {
+
+    @Schema(description = "领用人id", example = "1")
+    @NotNull(message = "领用人不能为空")
+    private Long employeeId;
+
+    @Schema(description = "固定资产信息表主键id", example = "1")
+    @NotNull(message = "领用资产不能为空")
+    private Long assetInfoId;
+
+    @Schema(description = "领用日期", example = "2024-08-09")
+    @NotBlank(message = "领用日期不能为空")
+    private String receiveDate;
+
+    @Schema(description = "领用原因", example = "领用时领用原因不能为空")
+    @NotBlank(message = "领用原因不能为空")
+    private String reason;
+
+}

+ 25 - 0
yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/controller/admin/assetreceiveinfo/vo/AssetReceiveInfoUpdateReqVO.java

@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.asset.controller.admin.assetreceiveinfo.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 固定资产归还 Request VO")
+@Data
+public class AssetReceiveInfoUpdateReqVO {
+
+    @Schema(description = "固定资产信息表主键id", example = "1")
+    @NotNull(message = "领用资产不能为空")
+    private Long assetInfoId;
+
+    @Schema(description = "归还日期", example = "2024-09-09")
+    @NotBlank(message = "归还日期不能为空")
+    private String returnDate;
+
+    @Schema(description = "归还原因", example = "归还时归还原因不能为空")
+    @NotBlank(message = "归还原因不能为空")
+    private String returnReason;
+
+}

+ 103 - 0
yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/dal/dataobject/assetinfo/AssetInfoDO.java

@@ -0,0 +1,103 @@
+package cn.iocoder.yudao.module.asset.dal.dataobject.assetinfo;
+
+import lombok.*;
+import java.util.*;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 固定资产信息 DO
+ *
+ * @author dp
+ */
+@TableName("finance_asset_info")
+@KeySequence("finance_asset_info_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class AssetInfoDO extends BaseDO {
+
+    /**
+     * 资产信息主键自增id
+     */
+    @TableId
+    private Long id;
+    /**
+     * 资产编号:年月日+uuid
+     */
+    private String assetInfoUuid;
+    /**
+     * 资产名称
+     */
+    private String name;
+    /**
+     * 备用字段:资产数量,默认为1
+     */
+    private Integer number;
+    /**
+     * 资产型号
+     */
+    private String typeNumber;
+    /**
+     * 资产序列号
+     */
+    private String serialNumber;
+    /**
+     * 购买日期
+     */
+    private String purchaseDate;
+    /**
+     * 资产化日期
+     */
+    private String capitalizationDate;
+    /**
+     * 折旧年限(大于0的自然数)
+     */
+    private Integer depreciationYear;
+    /**
+     * 资产状态:0可用 1占用 2报废
+     */
+    private String assetState;
+    /**
+     * 领用人id
+     */
+    private Long receiveEmployeeId;
+    /**
+     * 领用信息表主键id
+     */
+    private Long receiveInfoId;
+    /**
+     * 资产归属部门
+     */
+    private Long assetDeptId;
+    /**
+     * 资产归属地
+     */
+    private String assetPlace;
+    /**
+     * 资产管理负责人
+     */
+    private Long assetManagerEmployeeId;
+    /**
+     * 报废日期
+     */
+    private String retirementDate;
+    /**
+     * 报废原因
+     */
+    private String retirementReason;
+    /**
+     * 单据状态:0:已完成,1:作废
+     */
+    private String status;
+    /**
+     * 备注
+     */
+    private String remarks;
+
+}

+ 87 - 0
yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/dal/dataobject/assetreceiveinfo/AssetReceiveInfoDO.java

@@ -0,0 +1,87 @@
+package cn.iocoder.yudao.module.asset.dal.dataobject.assetreceiveinfo;
+
+import lombok.*;
+import java.util.*;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 固定资产领用信息 DO
+ *
+ * @author dp
+ */
+@TableName("finance_asset_receive_info")
+@KeySequence("finance_asset_receive_info_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class AssetReceiveInfoDO extends BaseDO {
+
+    /**
+     * 主键自增id
+     */
+    @TableId
+    private Long id;
+    /**
+     * 领用编号uuid
+     */
+    private String receiveInfoUuid;
+    /**
+     * 领用人id
+     */
+    private Long employeeId;
+    /**
+     * 部门id
+     */
+    private Long deptId;
+    /**
+     * 职位id
+     */
+    private Long postId;
+    /**
+     * 固定资产信息表主键id
+     */
+    private Long assetInfoId;
+    /**
+     * 固定资产名称
+     */
+    private String assetInfoName;
+    /**
+     * 领用日期
+     */
+    private String receiveDate;
+    /**
+     * 领用原因
+     */
+    private String reason;
+    /**
+     * 是否归还:0未归还,1已归还
+     */
+    private Integer returned;
+    /**
+     * 归还日期
+     */
+    private String returnDate;
+    /**
+     * 归还原因
+     */
+    private String returnReason;
+    /**
+     * 数据来源,0流程添加、1手动添加
+     */
+    private String infoSource;
+    /**
+     * 单据状态:0:已完成,1:作废
+     */
+    private String status;
+    /**
+     * 备注
+     */
+    private String remarks;
+
+}

+ 50 - 0
yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/dal/mysql/assetinfo/AssetInfoMapper.java

@@ -0,0 +1,50 @@
+package cn.iocoder.yudao.module.asset.dal.mysql.assetinfo;
+
+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.asset.controller.admin.assetinfo.vo.AssetInfoPageReqVO;
+import cn.iocoder.yudao.module.asset.controller.admin.assetinfo.vo.AssetInfoRespVO;
+import cn.iocoder.yudao.module.asset.dal.dataobject.assetinfo.AssetInfoDO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 固定资产信息 Mapper
+ *
+ * @author dp
+ */
+@Mapper
+public interface AssetInfoMapper extends BaseMapperX<AssetInfoDO> {
+
+    default PageResult<AssetInfoDO> selectPage(AssetInfoPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<AssetInfoDO>()
+                .eqIfPresent(AssetInfoDO::getAssetInfoUuid, reqVO.getAssetInfoUuid())
+                .likeIfPresent(AssetInfoDO::getName, reqVO.getName())
+                .eqIfPresent(AssetInfoDO::getTypeNumber, reqVO.getTypeNumber())
+                .eqIfPresent(AssetInfoDO::getSerialNumber, reqVO.getSerialNumber())
+                .betweenIfPresent(AssetInfoDO::getCapitalizationDate, reqVO.getCapitalizationDate())
+                .eqIfPresent(AssetInfoDO::getDepreciationYear, reqVO.getDepreciationYear())
+                .eqIfPresent(AssetInfoDO::getAssetState, reqVO.getAssetState())
+                .eqIfPresent(AssetInfoDO::getAssetDeptId, reqVO.getAssetDeptId())
+                .orderByDesc(AssetInfoDO::getId));
+    }
+
+    /**
+     * 查询资产信息的总条数
+     *
+     * @param pageReqVO 包含查询条件的分页请求对象
+     * @return 总条数
+     */
+    long selectPageCount(@Param("page") AssetInfoPageReqVO pageReqVO);
+
+    /**
+     * 根据分页条件查询资产信息列表
+     *
+     * @param pageReqVO 包含查询条件的分页请求对象
+     * @return 资产信息列表
+     */
+    List<AssetInfoRespVO> selectPageList(@Param("page") AssetInfoPageReqVO pageReqVO);
+}

+ 24 - 0
yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/dal/mysql/assetreceiveinfo/AssetReceiveInfoMapper.java

@@ -0,0 +1,24 @@
+package cn.iocoder.yudao.module.asset.dal.mysql.assetreceiveinfo;
+
+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.asset.controller.admin.assetreceiveinfo.vo.AssetReceiveInfoPageReqVO;
+import cn.iocoder.yudao.module.asset.dal.dataobject.assetreceiveinfo.AssetReceiveInfoDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 固定资产领用信息 Mapper
+ *
+ * @author dp
+ */
+@Mapper
+public interface AssetReceiveInfoMapper extends BaseMapperX<AssetReceiveInfoDO> {
+
+    default PageResult<AssetReceiveInfoDO> selectPage(AssetReceiveInfoPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<AssetReceiveInfoDO>()
+                .eqIfPresent(AssetReceiveInfoDO::getAssetInfoId, reqVO.getAssetInfoId())
+                .orderByAsc(AssetReceiveInfoDO::getId));
+    }
+
+}

+ 27 - 0
yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/framework/config/AssetWebConfiguration.java

@@ -0,0 +1,27 @@
+package cn.iocoder.yudao.module.asset.framework.config;
+
+import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration;
+import org.springdoc.core.GroupedOpenApi;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 资产模块的Web配置类
+ * 用于配置模块相关的Web功能,例如Swagger文档分组
+ */
+@Configuration(proxyBeanMethods = false)
+public class AssetWebConfiguration {
+
+    /**
+     * 配置Swagger文档的分组
+     * 这样可以将资产模块的API接口文档独立分组,便于在Swagger UI中管理和查看
+     *
+     * @return 分组配置对象
+     */
+    @Bean
+    public GroupedOpenApi assetGroupedOpenApi() {
+        return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("asset");
+    }
+
+}
+

+ 70 - 0
yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/service/assetinfo/AssetInfoService.java

@@ -0,0 +1,70 @@
+package cn.iocoder.yudao.module.asset.service.assetinfo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.asset.controller.admin.assetinfo.vo.AssetInfoPageReqVO;
+import cn.iocoder.yudao.module.asset.controller.admin.assetinfo.vo.AssetInfoRespVO;
+import cn.iocoder.yudao.module.asset.controller.admin.assetinfo.vo.AssetInfoRetireReqVO;
+import cn.iocoder.yudao.module.asset.controller.admin.assetinfo.vo.AssetInfoSaveReqVO;
+import cn.iocoder.yudao.module.asset.dal.dataobject.assetinfo.AssetInfoDO;
+
+import javax.validation.Valid;
+
+/**
+ * 固定资产信息 Service 接口
+ *
+ * @author dp
+ */
+public interface AssetInfoService {
+
+    /**
+     * 创建固定资产信息
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createInfo(@Valid AssetInfoSaveReqVO createReqVO);
+
+    /**
+     * 更新固定资产信息
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateInfo(@Valid AssetInfoSaveReqVO updateReqVO);
+
+    /**
+     * 更新固定资产信息
+     *
+     * @param updateReqVO 更新信息
+     */
+    void availableOrOccupiedAssetInfo(AssetInfoDO updateReqVO);
+
+    /**
+     * 删除固定资产信息
+     *
+     * @param id 编号
+     */
+    void deleteInfo(Long id);
+
+    /**
+     * 获得固定资产信息
+     *
+     * @param id 编号
+     * @return 固定资产信息
+     */
+    AssetInfoDO getInfo(Long id);
+
+    /**
+     * 获得固定资产信息分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 固定资产信息分页
+     */
+    PageResult<AssetInfoRespVO> getInfoPage(AssetInfoPageReqVO pageReqVO);
+
+    /**
+     * 废弃固定资产信息
+     *
+     * @param retireReqVO 报废信息
+     */
+    void retireInfo(AssetInfoRetireReqVO retireReqVO);
+}

+ 172 - 0
yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/service/assetinfo/AssetInfoServiceImpl.java

@@ -0,0 +1,172 @@
+package cn.iocoder.yudao.module.asset.service.assetinfo;
+
+import cn.hutool.core.util.IdUtil;
+import cn.iocoder.yudao.framework.common.exception.ErrorCode;
+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.security.core.util.SecurityFrameworkUtils;
+import cn.iocoder.yudao.module.asset.controller.admin.assetinfo.vo.AssetInfoPageReqVO;
+import cn.iocoder.yudao.module.asset.controller.admin.assetinfo.vo.AssetInfoRespVO;
+import cn.iocoder.yudao.module.asset.controller.admin.assetinfo.vo.AssetInfoRetireReqVO;
+import cn.iocoder.yudao.module.asset.controller.admin.assetinfo.vo.AssetInfoSaveReqVO;
+import cn.iocoder.yudao.module.asset.dal.dataobject.assetinfo.AssetInfoDO;
+import cn.iocoder.yudao.module.asset.dal.mysql.assetinfo.AssetInfoMapper;
+import cn.iocoder.yudao.module.asset.enums.AssetStateEnum;
+import cn.iocoder.yudao.module.asset.enums.AssetStatusEnum;
+import cn.iocoder.yudao.module.employee.api.EmployeeApi;
+import cn.iocoder.yudao.module.employee.api.dto.EmployeeRespDTO;
+import cn.iocoder.yudao.module.infra.api.file.FileApi;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.asset.enums.ErrorCodeConstants.INFO_NOT_EXISTS;
+import static cn.iocoder.yudao.module.asset.enums.ErrorCodeConstants.OCCUPIED_ASSET_NOT_ALLOWED_DELETE;
+
+/**
+ * 固定资产信息 Service 实现类
+ *
+ * @author dp
+ */
+@Service
+@Validated
+public class AssetInfoServiceImpl implements AssetInfoService {
+
+    @Resource
+    private AssetInfoMapper infoMapper;
+
+    @Resource
+    private EmployeeApi employeeApi;
+
+    @Resource
+    private FileApi fileApi;
+
+    @Override
+    public Long createInfo(AssetInfoSaveReqVO createReqVO) {
+        // 获取当前登录用户ID
+        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
+        // 通过用户ID获取当前登录员工信息
+        EmployeeRespDTO loginEmployee = employeeApi.getEmployeeByUserId(loginUserId);
+
+        // 将创建请求对象转换为资产信息实体对象
+        AssetInfoDO info = BeanUtils.toBean(createReqVO, AssetInfoDO.class);
+
+        // 生成资产信息的唯一标识(UUID),使用当前日期和随机UUID组合
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
+        String format = formatter.format(LocalDateTime.now());
+        info.setAssetInfoUuid(format + IdUtil.fastSimpleUUID());
+
+        // 设置资产状态为可用
+        info.setAssetState(AssetStateEnum.AVAILABLE.getState());
+
+        // 单据状态
+        info.setStatus(AssetStatusEnum.COMPLETED.getStatus());
+
+        // 设置创建人为当前登录员工
+        info.setCreator(String.valueOf(loginEmployee.getId()));
+
+        // 插入资产信息到数据库
+        infoMapper.insert(info);
+
+        // 更新文件业务关系
+        fileApi.updateFileBiz(createReqVO.getFileIdList(), info.getAssetInfoUuid());
+
+        // 返回创建的资产信息的ID
+        return info.getId();
+    }
+    @Override
+    public void updateInfo(AssetInfoSaveReqVO updateReqVO) {
+        // 校验存在
+        AssetInfoDO assetInfoDO = validateInfoExists(updateReqVO.getId());
+        // 更新
+        AssetInfoDO updateObj = BeanUtils.toBean(updateReqVO, AssetInfoDO.class);
+
+        // 附件
+        fileApi.updateFileBiz(updateReqVO.getFileIdList(), assetInfoDO.getAssetInfoUuid());
+
+        infoMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void availableOrOccupiedAssetInfo(AssetInfoDO updateReqVO) {
+        // 校验存在
+        AssetInfoDO assetInfoDO = validateInfoExists(updateReqVO.getId());
+        LambdaUpdateWrapper<AssetInfoDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
+        lambdaUpdateWrapper.set(AssetInfoDO::getAssetState, updateReqVO.getAssetState())
+                .set(AssetInfoDO::getReceiveEmployeeId, updateReqVO.getReceiveEmployeeId())
+                .set(AssetInfoDO::getReceiveInfoId, updateReqVO.getReceiveInfoId())
+                .eq(AssetInfoDO::getId, updateReqVO.getId());
+       infoMapper.update(lambdaUpdateWrapper);
+    }
+
+    @Override
+    public void deleteInfo(Long id) {
+        // 校验存在
+        AssetInfoDO assetInfoDO = validateInfoExists(id);
+        // 校验能否删除
+        // 占用中的不能删除
+        if (AssetStateEnum.OCCUPIED.getState().equals(assetInfoDO.getAssetState())) {
+            throw exception(OCCUPIED_ASSET_NOT_ALLOWED_DELETE);
+        }
+        // 领用中的资产不能删除
+        // 删除
+        infoMapper.deleteById(id);
+    }
+
+    private AssetInfoDO validateInfoExists(Long id) {
+        AssetInfoDO assetInfoDO = infoMapper.selectById(id);
+        if (assetInfoDO == null) {
+            throw exception(INFO_NOT_EXISTS);
+        }
+        return assetInfoDO;
+    }
+
+    @Override
+    public AssetInfoDO getInfo(Long id) {
+        return infoMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<AssetInfoRespVO> getInfoPage(AssetInfoPageReqVO pageReqVO) {
+        // 分页起始位置
+        pageReqVO.setPageNo((pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize());
+
+        // 查询总记录数
+        long pageCount = -1;
+        if (!PageParam.PAGE_SIZE_NONE.equals(pageReqVO.getPageSize())) {
+            pageCount = infoMapper.selectPageCount(pageReqVO);
+        }
+
+        // 查询分页数据
+        List<AssetInfoRespVO> pageList = infoMapper.selectPageList(pageReqVO);
+
+        return new PageResult<>(pageList, pageCount);
+    }
+
+    @Override
+    public void retireInfo(AssetInfoRetireReqVO retireReqVO) {
+        Long id = retireReqVO.getId();
+        AssetInfoDO assetInfoDO = validateInfoExists(id);
+        if (AssetStateEnum.OCCUPIED.getState().equals(assetInfoDO.getAssetState())) {
+            throw exception(new ErrorCode(OCCUPIED_ASSET_NOT_ALLOWED_DELETE.getCode(), "资产正在使用,不能报废"));
+        }
+        if (AssetStateEnum.RETIRED.getState().equals(assetInfoDO.getAssetState())) {
+            throw exception(new ErrorCode(OCCUPIED_ASSET_NOT_ALLOWED_DELETE.getCode(), "资产已报废,不能重复报废"));
+        }
+        AssetInfoDO build = AssetInfoDO.builder()
+                .id(id)
+                .assetState(AssetStateEnum.RETIRED.getState())
+                .retirementDate(retireReqVO.getRetirementDate())
+                .retirementReason(retireReqVO.getRetirementReason())
+                .build();
+        infoMapper.updateById(build);
+    }
+
+}

+ 56 - 0
yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/service/assetreceiveinfo/AssetReceiveInfoService.java

@@ -0,0 +1,56 @@
+package cn.iocoder.yudao.module.asset.service.assetreceiveinfo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.asset.controller.admin.assetreceiveinfo.vo.AssetReceiveInfoPageReqVO;
+import cn.iocoder.yudao.module.asset.controller.admin.assetreceiveinfo.vo.AssetReceiveInfoSaveReqVO;
+import cn.iocoder.yudao.module.asset.controller.admin.assetreceiveinfo.vo.AssetReceiveInfoUpdateReqVO;
+import cn.iocoder.yudao.module.asset.dal.dataobject.assetreceiveinfo.AssetReceiveInfoDO;
+
+import javax.validation.Valid;
+
+/**
+ * 固定资产领用信息 Service 接口
+ *
+ * @author dp
+ */
+public interface AssetReceiveInfoService {
+
+    /**
+     * 创建固定资产领用信息
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createReceiveInfo(@Valid AssetReceiveInfoSaveReqVO createReqVO);
+
+    /**
+     * 更新固定资产领用信息
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateReceiveInfo(@Valid AssetReceiveInfoUpdateReqVO updateReqVO);
+
+    /**
+     * 删除固定资产领用信息
+     *
+     * @param id 编号
+     */
+    void deleteReceiveInfo(Long id);
+
+    /**
+     * 获得固定资产领用信息
+     *
+     * @param id 编号
+     * @return 固定资产领用信息
+     */
+    AssetReceiveInfoDO getReceiveInfo(Long id);
+
+    /**
+     * 获得固定资产领用信息分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 固定资产领用信息分页
+     */
+    PageResult<AssetReceiveInfoDO> getReceiveInfoPage(AssetReceiveInfoPageReqVO pageReqVO);
+
+}

+ 180 - 0
yudao-module-finance/yudao-module-asset-biz/src/main/java/cn/iocoder/yudao/module/asset/service/assetreceiveinfo/AssetReceiveInfoServiceImpl.java

@@ -0,0 +1,180 @@
+package cn.iocoder.yudao.module.asset.service.assetreceiveinfo;
+
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.exception.ErrorCode;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
+import cn.iocoder.yudao.module.asset.controller.admin.assetreceiveinfo.vo.AssetReceiveInfoPageReqVO;
+import cn.iocoder.yudao.module.asset.controller.admin.assetreceiveinfo.vo.AssetReceiveInfoSaveReqVO;
+import cn.iocoder.yudao.module.asset.controller.admin.assetreceiveinfo.vo.AssetReceiveInfoUpdateReqVO;
+import cn.iocoder.yudao.module.asset.dal.dataobject.assetinfo.AssetInfoDO;
+import cn.iocoder.yudao.module.asset.dal.dataobject.assetreceiveinfo.AssetReceiveInfoDO;
+import cn.iocoder.yudao.module.asset.dal.mysql.assetreceiveinfo.AssetReceiveInfoMapper;
+import cn.iocoder.yudao.module.asset.enums.AssetReturnStateEnum;
+import cn.iocoder.yudao.module.asset.enums.AssetStateEnum;
+import cn.iocoder.yudao.module.asset.service.assetinfo.AssetInfoService;
+import cn.iocoder.yudao.module.employee.api.EmployeeApi;
+import cn.iocoder.yudao.module.employee.api.dto.EmployeeRespDTO;
+import cn.iocoder.yudao.module.system.api.dept.DeptApi;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.util.Objects;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.asset.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.module.employee.enums.ErrorCodeConstants.EMPLOYEE_INFO_NOT_EXISTS;
+
+/**
+ * 固定资产领用信息 Service 实现类
+ *
+ * @author dp
+ */
+@Service
+@Validated
+public class AssetReceiveInfoServiceImpl implements AssetReceiveInfoService {
+
+    @Resource
+    private AssetReceiveInfoMapper receiveInfoMapper;
+
+    @Resource
+    private AssetInfoService assetInfoService;
+
+    @Resource
+    private EmployeeApi employeeApi;
+
+    @Resource
+    private DeptApi deptApi;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Long createReceiveInfo(AssetReceiveInfoSaveReqVO createReqVO) {
+        // 登录人
+        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
+        EmployeeRespDTO loginEmployee = employeeApi.getEmployeeByUserId(loginUserId);
+        if (Objects.isNull(loginEmployee)) {
+            throw exception(new ErrorCode(EMPLOYEE_INFO_NOT_EXISTS.getCode(), "当前登录人员无员工信息"));
+        }
+        Long assetInfoId = createReqVO.getAssetInfoId();
+        AssetInfoDO assetInfoDO = assetInfoService.getInfo(assetInfoId);
+        if (Objects.isNull(assetInfoDO)) {
+            throw exception(INFO_NOT_EXISTS);
+        }
+        if (!AssetStateEnum.AVAILABLE.getState().equals(assetInfoDO.getAssetState())) {
+            throw exception(ASSET_INFO_NOT_AVAILABLE);
+        }
+        Long employeeId = createReqVO.getEmployeeId();
+        if (Objects.isNull(employeeId)) {
+            throw exception(ASSET_RECEIVE_EMPLOYEE_NOT_NULL);
+        }
+        String receiveDate = createReqVO.getReceiveDate();
+        if (StrUtil.isBlank(receiveDate)) {
+            throw exception(ASSET_RECEIVE_DATE_NOT_BLANK);
+        }
+        if (StrUtil.isBlank(createReqVO.getReason())) {
+            throw exception(ASSET_RECEIVE_REASON_NOT_BLANK);
+        }
+        // 插入
+        AssetReceiveInfoDO receiveInfo = BeanUtils.toBean(createReqVO, AssetReceiveInfoDO.class);
+        // uuid
+        receiveInfo.setReceiveInfoUuid(IdUtil.fastSimpleUUID());
+        // 资产名称
+        receiveInfo.setAssetInfoName(assetInfoDO.getName());
+        // 未归还
+        receiveInfo.setReturned(AssetReturnStateEnum.NOT_RETURNED.getState());
+        // 创建人
+        receiveInfo.setCreator(String.valueOf(loginEmployee.getId()));
+        // 操作人
+        receiveInfo.setUpdater(String.valueOf(loginEmployee.getId()));
+        // 部门
+        receiveInfo.setDeptId(loginEmployee.getDeptId());
+        // 职位
+        receiveInfo.setPostId(loginEmployee.getPostId());
+        receiveInfoMapper.insert(receiveInfo);
+
+        // 领用成功后修改资产状态
+        AssetInfoDO build = AssetInfoDO.builder()
+                .id(assetInfoId)
+                .receiveEmployeeId(receiveInfo.getEmployeeId())
+                .receiveInfoId(receiveInfo.getId())
+                .assetState(AssetStateEnum.OCCUPIED.getState())
+                .build();
+        assetInfoService.availableOrOccupiedAssetInfo(build);
+        // 返回
+        return receiveInfo.getId();
+    }
+
+    @Override
+    public void updateReceiveInfo(AssetReceiveInfoUpdateReqVO updateReqVO) {
+        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
+        EmployeeRespDTO loginEmployee = employeeApi.getEmployeeByUserId(loginUserId);
+
+        AssetInfoDO assetInfoDO = assetInfoService.getInfo(updateReqVO.getAssetInfoId());
+        if (Objects.isNull(assetInfoDO)) {
+            throw exception(INFO_NOT_EXISTS);
+        }
+        if (!AssetStateEnum.OCCUPIED.getState().equals(assetInfoDO.getAssetState())) {
+            throw exception(ASSET_INFO_NOT_OCCUPIED);
+        }
+
+        Long receiveInfoId = assetInfoDO.getReceiveInfoId();
+        // 校验存在
+        AssetReceiveInfoDO assetReceiveInfoDO = validateReceiveInfoExists(receiveInfoId);
+        String returnDate = updateReqVO.getReturnDate();
+        if (StrUtil.isBlank(returnDate)) {
+            throw exception(ASSET_RETURN_DATE_NOT_BLANK);
+        }
+        String returnReason = updateReqVO.getReturnReason();
+        if (StrUtil.isBlank(returnReason)) {
+            throw exception(ASSET_RETURN_REASON_NOT_BLANK);
+        }
+        // 更新
+        AssetReceiveInfoDO updateObj = BeanUtils.toBean(updateReqVO, AssetReceiveInfoDO.class);
+        // 已归还
+        updateObj.setReturned(AssetReturnStateEnum.RETURNED.getState());
+        // 操作人
+        updateObj.setUpdater(String.valueOf(loginEmployee.getId()));
+        updateObj.setId(receiveInfoId);
+        receiveInfoMapper.updateById(updateObj);
+
+        // 更新对应资产状态为可用,同时置空领用信息
+        AssetInfoDO build = AssetInfoDO.builder()
+                .id(assetInfoDO.getId())
+                .assetState(AssetStateEnum.AVAILABLE.getState())
+                .receiveEmployeeId(null)
+                .receiveInfoId(null)
+                .build();
+        assetInfoService.availableOrOccupiedAssetInfo(build);
+    }
+
+    @Override
+    public void deleteReceiveInfo(Long id) {
+        // 校验存在
+        validateReceiveInfoExists(id);
+        // 删除
+        receiveInfoMapper.deleteById(id);
+    }
+
+    private AssetReceiveInfoDO validateReceiveInfoExists(Long id) {
+        AssetReceiveInfoDO assetReceiveInfoDO = receiveInfoMapper.selectById(id);
+        if (assetReceiveInfoDO == null) {
+            throw exception(RECEIVE_INFO_NOT_EXISTS);
+        }
+        return assetReceiveInfoDO;
+    }
+
+    @Override
+    public AssetReceiveInfoDO getReceiveInfo(Long id) {
+        return receiveInfoMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<AssetReceiveInfoDO> getReceiveInfoPage(AssetReceiveInfoPageReqVO pageReqVO) {
+        return receiveInfoMapper.selectPage(pageReqVO);
+    }
+
+}

+ 124 - 0
yudao-module-finance/yudao-module-asset-biz/src/main/resources/mapper/assetinfo/AssetInfoMapper.xml

@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.iocoder.yudao.module.asset.dal.mysql.assetinfo.AssetInfoMapper">
+
+    <!--
+        一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
+        无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
+        代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
+        文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
+     -->
+
+    <select id="selectPageCount" resultType="java.lang.Long">
+        SELECT
+            count(fai.id)
+        FROM
+        finance_asset_info fai
+        LEFT JOIN employee_info ei ON ei.id = fai.receive_employee_id AND ei.deleted = 0
+        LEFT JOIN employee_info ei2 ON ei2.id = fai.asset_manager_employee_id AND ei2.deleted = 0
+        LEFT JOIN system_dept sd ON sd.id = fai.asset_dept_id AND sd.deleted = 0
+        WHERE
+        fai.deleted = 0
+        <if test="page.assetInfoUuid != null and page.assetInfoUuid != ''">
+            AND fai.asset_info_uuid like concat('%',#{page.assetInfoUuid},'%')
+        </if>
+        <if test="page.name != null and page.name != ''">
+            AND fai.name like concat('%',#{page.name},'%')
+        </if>
+        <if test="page.typeNumber != null and page.typeNumber != ''">
+            AND fai.type_number like concat('%',#{page.typeNumber},'%')
+        </if>
+        <if test="page.serialNumber != null and page.serialNumber != ''">
+            AND fai.serial_number like concat('%',#{page.serialNumber},'%')
+        </if>
+        <if test="page.capitalizationDate != null and page.capitalizationDate.length > 0">
+            AND fai.capitalization_date BETWEEN #{page.capitalizationDate[0]} AND #{page.capitalizationDate[1]}
+        </if>
+        <if test="page.depreciationYear != null">
+            AND fai.depreciation_year = #{page.depreciationYear}
+        </if>
+        <if test="page.assetState != null and page.assetState != ''">
+            AND fai.asset_state = #{page.assetState}
+        </if>
+        <if test="page.receiveEmployeeName != null and page.receiveEmployeeName != ''">
+            AND ei.name like concat('%',#{page.receiveEmployeeName},'%')
+        </if>
+        <if test="page.assetDeptId != null">
+            AND fai.asset_dept_id = #{page.assetDeptId}
+        </if>
+    </select>
+    <select id="selectPageList"
+            resultType="cn.iocoder.yudao.module.asset.controller.admin.assetinfo.vo.AssetInfoRespVO">
+        SELECT
+            fai.id,
+            fai.asset_info_uuid,
+            fai.`name`,
+            fai.number,
+            fai.type_number,
+            fai.serial_number,
+            fai.purchase_date,
+            fai.capitalization_date,
+            fai.depreciation_year,
+            fai.asset_state,
+            CASE
+                WHEN fai.asset_state = '0' THEN '可用'
+                WHEN fai.asset_state = '1' THEN '占用'
+                WHEN fai.asset_state = '2' THEN '已报废'
+            END AS assetStateDesc,
+            fai.receive_employee_id,
+            ei.name AS receiveEmployeeName,
+            fai.receive_info_id,
+            fai.asset_dept_id,
+            sd.name AS assetDeptName,
+            fai.asset_place,
+            fai.asset_manager_employee_id,
+            ei2.name AS assetManagerEmployeeName,
+            fai.retirement_date,
+            fai.retirement_reason,
+            fai.`status`,
+            CASE
+               WHEN fai.`status` = '0' THEN '已完成'
+               WHEN fai.`status` = '1' THEN '作废'
+            END AS statusDesc,
+            fai.remarks
+        FROM
+            finance_asset_info fai
+                LEFT JOIN employee_info ei ON ei.id = fai.receive_employee_id AND ei.deleted = 0
+                LEFT JOIN employee_info ei2 ON ei2.id = fai.asset_manager_employee_id AND ei2.deleted = 0
+                LEFT JOIN system_dept sd ON sd.id = fai.asset_dept_id AND sd.deleted = 0
+        WHERE
+            fai.deleted = 0
+        <if test="page.assetInfoUuid != null and page.assetInfoUuid != ''">
+            AND fai.asset_info_uuid like concat('%',#{page.assetInfoUuid},'%')
+        </if>
+        <if test="page.name != null and page.name != ''">
+            AND fai.name like concat('%',#{page.name},'%')
+        </if>
+        <if test="page.typeNumber != null and page.typeNumber != ''">
+            AND fai.type_number like concat('%',#{page.typeNumber},'%')
+        </if>
+        <if test="page.serialNumber != null and page.serialNumber != ''">
+            AND fai.serial_number like concat('%',#{page.serialNumber},'%')
+        </if>
+        <if test="page.capitalizationDate != null and page.capitalizationDate.length > 0">
+            AND fai.capitalization_date BETWEEN #{page.capitalizationDate[0]} AND #{page.capitalizationDate[1]}
+        </if>
+        <if test="page.depreciationYear != null">
+            AND fai.depreciation_year = #{page.depreciationYear}
+        </if>
+        <if test="page.assetState != null and page.assetState != ''">
+            AND fai.asset_state = #{page.assetState}
+        </if>
+        <if test="page.receiveEmployeeName != null and page.receiveEmployeeName != ''">
+            AND ei.name like concat('%',#{page.receiveEmployeeName},'%')
+        </if>
+        <if test="page.assetDeptId != null">
+            AND fai.asset_dept_id = #{page.assetDeptId}
+        </if>
+        ORDER BY
+            fai.create_time DESC
+        <if test="page.pageSize != -1">
+            LIMIT #{page.pageNo}, #{page.pageSize}
+        </if>
+    </select>
+</mapper>

+ 12 - 0
yudao-module-finance/yudao-module-asset-biz/src/main/resources/mapper/assetreceiveinfo/AssetReceiveInfoMapper.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.iocoder.yudao.module.asset.dal.mysql.assetreceiveinfo.AssetReceiveInfoMapper">
+
+    <!--
+        一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
+        无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
+        代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
+        文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
+     -->
+
+</mapper>

+ 162 - 0
yudao-module-finance/yudao-module-asset-biz/src/test/java/cn/iocoder/yudao/module/asset/service/assetinfo/AssetInfoServiceImplTest.java

@@ -0,0 +1,162 @@
+// package cn.iocoder.yudao.module.asset.service.assetinfo;
+//
+// import org.junit.jupiter.api.Disabled;
+// import org.junit.jupiter.api.Test;
+// import org.springframework.boot.test.mock.mockito.MockBean;
+//
+// import javax.annotation.Resource;
+//
+// import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+//
+// import cn.iocoder.yudao.module.asset.controller.admin.assetinfo.vo.*;
+// import cn.iocoder.yudao.module.asset.dal.dataobject.assetinfo.AssetInfoDO;
+// import cn.iocoder.yudao.module.asset.dal.mysql.assetinfo.AssetInfoMapper;
+// import cn.iocoder.yudao.framework.common.pojo.PageResult;
+//
+// import javax.annotation.Resource;
+// import org.springframework.context.annotation.Import;
+// import java.util.*;
+// import java.time.LocalDateTime;
+//
+// import static cn.hutool.core.util.RandomUtil.*;
+// import static cn.iocoder.yudao.module.asset.enums.ErrorCodeConstants.*;
+// import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
+// import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
+// import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
+// import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
+// import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
+// import static org.junit.jupiter.api.Assertions.*;
+// import static org.mockito.Mockito.*;
+//
+// /**
+//  * {@link AssetInfoServiceImpl} 的单元测试类
+//  *
+//  * @author dp
+//  */
+// @Import(AssetInfoServiceImpl.class)
+// public class AssetInfoServiceImplTest extends BaseDbUnitTest {
+//
+//     @Resource
+//     private AssetInfoServiceImpl infoService;
+//
+//     @Resource
+//     private AssetInfoMapper infoMapper;
+//
+//     @Test
+//     public void testCreateInfo_success() {
+//         // 准备参数
+//         AssetInfoSaveReqVO createReqVO = randomPojo(AssetInfoSaveReqVO.class).setId(null);
+//
+//         // 调用
+//         Long infoId = infoService.createInfo(createReqVO);
+//         // 断言
+//         assertNotNull(infoId);
+//         // 校验记录的属性是否正确
+//         AssetInfoDO info = infoMapper.selectById(infoId);
+//         assertPojoEquals(createReqVO, info, "id");
+//     }
+//
+//     @Test
+//     public void testUpdateInfo_success() {
+//         // mock 数据
+//         AssetInfoDO dbInfo = randomPojo(AssetInfoDO.class);
+//         infoMapper.insert(dbInfo);// @Sql: 先插入出一条存在的数据
+//         // 准备参数
+//         AssetInfoSaveReqVO updateReqVO = randomPojo(AssetInfoSaveReqVO.class, o -> {
+//             o.setId(dbInfo.getId()); // 设置更新的 ID
+//         });
+//
+//         // 调用
+//         infoService.updateInfo(updateReqVO);
+//         // 校验是否更新正确
+//         AssetInfoDO info = infoMapper.selectById(updateReqVO.getId()); // 获取最新的
+//         assertPojoEquals(updateReqVO, info);
+//     }
+//
+//     @Test
+//     public void testUpdateInfo_notExists() {
+//         // 准备参数
+//         AssetInfoSaveReqVO updateReqVO = randomPojo(AssetInfoSaveReqVO.class);
+//
+//         // 调用, 并断言异常
+//         assertServiceException(() -> infoService.updateInfo(updateReqVO), INFO_NOT_EXISTS);
+//     }
+//
+//     @Test
+//     public void testDeleteInfo_success() {
+//         // mock 数据
+//         AssetInfoDO dbInfo = randomPojo(AssetInfoDO.class);
+//         infoMapper.insert(dbInfo);// @Sql: 先插入出一条存在的数据
+//         // 准备参数
+//         Long id = dbInfo.getId();
+//
+//         // 调用
+//         infoService.deleteInfo(id);
+//        // 校验数据不存在了
+//        assertNull(infoMapper.selectById(id));
+//     }
+//
+//     @Test
+//     public void testDeleteInfo_notExists() {
+//         // 准备参数
+//         Long id = randomLongId();
+//
+//         // 调用, 并断言异常
+//         assertServiceException(() -> infoService.deleteInfo(id), INFO_NOT_EXISTS);
+//     }
+//
+//     @Test
+//     @Disabled  // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
+//     public void testGetInfoPage() {
+//        // mock 数据
+//        AssetInfoDO dbInfo = randomPojo(AssetInfoDO.class, o -> { // 等会查询到
+//            o.setAssetInfoUuid(null);
+//            o.setName(null);
+//            o.setTypeNumber(null);
+//            o.setSerialNumber(null);
+//            o.setCapitalizationDate(null);
+//            o.setDepreciationYear(null);
+//            o.setAssetState(null);
+//            o.setReceiveEmployeeId(null);
+//            o.setAssetDeptId(null);
+//        });
+//        infoMapper.insert(dbInfo);
+//        // 测试 assetInfoUuid 不匹配
+//        infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setAssetInfoUuid(null)));
+//        // 测试 name 不匹配
+//        infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setName(null)));
+//        // 测试 typeNumber 不匹配
+//        infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setTypeNumber(null)));
+//        // 测试 serialNumber 不匹配
+//        infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setSerialNumber(null)));
+//        // 测试 capitalizationDate 不匹配
+//        infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setCapitalizationDate(null)));
+//        // 测试 depreciationYear 不匹配
+//        infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setDepreciationYear(null)));
+//        // 测试 assetState 不匹配
+//        infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setAssetState(null)));
+//        // 测试 receiveEmployeeId 不匹配
+//        infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setReceiveEmployeeId(null)));
+//        // 测试 assetDeptId 不匹配
+//        infoMapper.insert(cloneIgnoreId(dbInfo, o -> o.setAssetDeptId(null)));
+//        // 准备参数
+//        AssetInfoPageReqVO reqVO = new AssetInfoPageReqVO();
+//        reqVO.setAssetInfoUuid(null);
+//        reqVO.setName(null);
+//        reqVO.setTypeNumber(null);
+//        reqVO.setSerialNumber(null);
+//        reqVO.setCapitalizationDate(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+//        reqVO.setDepreciationYear(null);
+//        reqVO.setAssetState(null);
+//        reqVO.setReceiveEmployeeId(null);
+//        reqVO.setAssetDeptId(null);
+//
+//        // 调用
+//        PageResult<AssetInfoDO> pageResult = infoService.getInfoPage(reqVO);
+//        // 断言
+//        assertEquals(1, pageResult.getTotal());
+//        assertEquals(1, pageResult.getList().size());
+//        assertPojoEquals(dbInfo, pageResult.getList().get(0));
+//     }
+//
+// }

+ 162 - 0
yudao-module-finance/yudao-module-asset-biz/src/test/java/cn/iocoder/yudao/module/asset/service/assetreceiveinfo/AssetReceiveInfoServiceImplTest.java

@@ -0,0 +1,162 @@
+// package cn.iocoder.yudao.module.asset.service.assetreceiveinfo;
+//
+// import org.junit.jupiter.api.Disabled;
+// import org.junit.jupiter.api.Test;
+// import org.springframework.boot.test.mock.mockito.MockBean;
+//
+// import javax.annotation.Resource;
+//
+// import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+//
+// import cn.iocoder.yudao.module.asset.controller.admin.assetreceiveinfo.vo.*;
+// import cn.iocoder.yudao.module.asset.dal.dataobject.assetreceiveinfo.AssetReceiveInfoDO;
+// import cn.iocoder.yudao.module.asset.dal.mysql.assetreceiveinfo.AssetReceiveInfoMapper;
+// import cn.iocoder.yudao.framework.common.pojo.PageResult;
+//
+// import javax.annotation.Resource;
+// import org.springframework.context.annotation.Import;
+// import java.util.*;
+// import java.time.LocalDateTime;
+//
+// import static cn.hutool.core.util.RandomUtil.*;
+// import static cn.iocoder.yudao.module.asset.enums.ErrorCodeConstants.*;
+// import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
+// import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
+// import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
+// import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
+// import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
+// import static org.junit.jupiter.api.Assertions.*;
+// import static org.mockito.Mockito.*;
+//
+// /**
+//  * {@link AssetReceiveInfoServiceImpl} 的单元测试类
+//  *
+//  * @author dp
+//  */
+// @Import(AssetReceiveInfoServiceImpl.class)
+// public class AssetReceiveInfoServiceImplTest extends BaseDbUnitTest {
+//
+//     @Resource
+//     private AssetReceiveInfoServiceImpl receiveInfoService;
+//
+//     @Resource
+//     private AssetReceiveInfoMapper receiveInfoMapper;
+//
+//     @Test
+//     public void testCreateReceiveInfo_success() {
+//         // 准备参数
+//         AssetReceiveInfoSaveReqVO createReqVO = randomPojo(AssetReceiveInfoSaveReqVO.class).setId(null);
+//
+//         // 调用
+//         Long receiveInfoId = receiveInfoService.createReceiveInfo(createReqVO);
+//         // 断言
+//         assertNotNull(receiveInfoId);
+//         // 校验记录的属性是否正确
+//         AssetReceiveInfoDO receiveInfo = receiveInfoMapper.selectById(receiveInfoId);
+//         assertPojoEquals(createReqVO, receiveInfo, "id");
+//     }
+//
+//     @Test
+//     public void testUpdateReceiveInfo_success() {
+//         // mock 数据
+//         AssetReceiveInfoDO dbReceiveInfo = randomPojo(AssetReceiveInfoDO.class);
+//         receiveInfoMapper.insert(dbReceiveInfo);// @Sql: 先插入出一条存在的数据
+//         // 准备参数
+//         AssetReceiveInfoSaveReqVO updateReqVO = randomPojo(AssetReceiveInfoSaveReqVO.class, o -> {
+//             o.setId(dbReceiveInfo.getId()); // 设置更新的 ID
+//         });
+//
+//         // 调用
+//         receiveInfoService.updateReceiveInfo(updateReqVO);
+//         // 校验是否更新正确
+//         AssetReceiveInfoDO receiveInfo = receiveInfoMapper.selectById(updateReqVO.getId()); // 获取最新的
+//         assertPojoEquals(updateReqVO, receiveInfo);
+//     }
+//
+//     @Test
+//     public void testUpdateReceiveInfo_notExists() {
+//         // 准备参数
+//         AssetReceiveInfoSaveReqVO updateReqVO = randomPojo(AssetReceiveInfoSaveReqVO.class);
+//
+//         // 调用, 并断言异常
+//         assertServiceException(() -> receiveInfoService.updateReceiveInfo(updateReqVO), RECEIVE_INFO_NOT_EXISTS);
+//     }
+//
+//     @Test
+//     public void testDeleteReceiveInfo_success() {
+//         // mock 数据
+//         AssetReceiveInfoDO dbReceiveInfo = randomPojo(AssetReceiveInfoDO.class);
+//         receiveInfoMapper.insert(dbReceiveInfo);// @Sql: 先插入出一条存在的数据
+//         // 准备参数
+//         Long id = dbReceiveInfo.getId();
+//
+//         // 调用
+//         receiveInfoService.deleteReceiveInfo(id);
+//        // 校验数据不存在了
+//        assertNull(receiveInfoMapper.selectById(id));
+//     }
+//
+//     @Test
+//     public void testDeleteReceiveInfo_notExists() {
+//         // 准备参数
+//         Long id = randomLongId();
+//
+//         // 调用, 并断言异常
+//         assertServiceException(() -> receiveInfoService.deleteReceiveInfo(id), RECEIVE_INFO_NOT_EXISTS);
+//     }
+//
+//     @Test
+//     @Disabled  // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
+//     public void testGetReceiveInfoPage() {
+//        // mock 数据
+//        AssetReceiveInfoDO dbReceiveInfo = randomPojo(AssetReceiveInfoDO.class, o -> { // 等会查询到
+//            o.setEmployeeId(null);
+//            o.setDeptId(null);
+//            o.setPostId(null);
+//            o.setAssetInfoName(null);
+//            o.setReceiveDate(null);
+//            o.setReturned(null);
+//            o.setReturnDate(null);
+//            o.setInfoSource(null);
+//            o.setCreator(null);
+//        });
+//        receiveInfoMapper.insert(dbReceiveInfo);
+//        // 测试 employeeId 不匹配
+//        receiveInfoMapper.insert(cloneIgnoreId(dbReceiveInfo, o -> o.setEmployeeId(null)));
+//        // 测试 deptId 不匹配
+//        receiveInfoMapper.insert(cloneIgnoreId(dbReceiveInfo, o -> o.setDeptId(null)));
+//        // 测试 postId 不匹配
+//        receiveInfoMapper.insert(cloneIgnoreId(dbReceiveInfo, o -> o.setPostId(null)));
+//        // 测试 assetInfoName 不匹配
+//        receiveInfoMapper.insert(cloneIgnoreId(dbReceiveInfo, o -> o.setAssetInfoName(null)));
+//        // 测试 receiveDate 不匹配
+//        receiveInfoMapper.insert(cloneIgnoreId(dbReceiveInfo, o -> o.setReceiveDate(null)));
+//        // 测试 returned 不匹配
+//        receiveInfoMapper.insert(cloneIgnoreId(dbReceiveInfo, o -> o.setReturned(null)));
+//        // 测试 returnDate 不匹配
+//        receiveInfoMapper.insert(cloneIgnoreId(dbReceiveInfo, o -> o.setReturnDate(null)));
+//        // 测试 infoSource 不匹配
+//        receiveInfoMapper.insert(cloneIgnoreId(dbReceiveInfo, o -> o.setInfoSource(null)));
+//        // 测试 creator 不匹配
+//        receiveInfoMapper.insert(cloneIgnoreId(dbReceiveInfo, o -> o.setCreator(null)));
+//        // 准备参数
+//        AssetReceiveInfoPageReqVO reqVO = new AssetReceiveInfoPageReqVO();
+//        reqVO.setEmployeeId(null);
+//        reqVO.setDeptId(null);
+//        reqVO.setPostId(null);
+//        reqVO.setAssetInfoName(null);
+//        reqVO.setReceiveDate(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+//        reqVO.setReturned(null);
+//        reqVO.setReturnDate(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+//        reqVO.setInfoSource(null);
+//        reqVO.setCreator(null);
+//
+//        // 调用
+//        PageResult<AssetReceiveInfoDO> pageResult = receiveInfoService.getReceiveInfoPage(reqVO);
+//        // 断言
+//        assertEquals(1, pageResult.getTotal());
+//        assertEquals(1, pageResult.getList().size());
+//        assertPojoEquals(dbReceiveInfo, pageResult.getList().get(0));
+//     }
+//
+// }

+ 1 - 1
yudao-module-finance/yudao-module-cash-biz/src/main/java/cn/iocoder/yudao/module/cash/service/paymentinfo/PaymentInfoServiceImpl.java

@@ -107,7 +107,7 @@ public class PaymentInfoServiceImpl implements PaymentInfoService {
 
     @Override
     public PageResult<PaymentInfoRespVO> getPaymentInfoPage(PaymentInfoPageReqVO pageReqVO) {
-        pageReqVO.setPageNo(pageReqVO.getPageNo() - 1);
+        pageReqVO.setPageNo((pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize());
 
         long pageCount = -1;
         if (!PageParam.PAGE_SIZE_NONE.equals(pageReqVO.getPageSize())) {

+ 1 - 1
yudao-module-finance/yudao-module-cash-biz/src/main/java/cn/iocoder/yudao/module/cash/service/refundinfo/RefundInfoServiceImpl.java

@@ -102,7 +102,7 @@ public class RefundInfoServiceImpl implements RefundInfoService {
 
     @Override
     public PageResult<RefundInfoRespVO> getRefundInfoPage(RefundInfoPageReqVO pageReqVO) {
-        pageReqVO.setPageNo(pageReqVO.getPageNo() - 1);
+        pageReqVO.setPageNo((pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize());
 
         long pageCount = -1;
         if (!PageParam.PAGE_SIZE_NONE.equals(pageReqVO.getPageSize())) {

+ 35 - 0
yudao-module-finance/yudao-module-contract-api/src/main/java/cn/iocoder/yudao/module/contract/enums/ContractStatusEnum.java

@@ -0,0 +1,35 @@
+package cn.iocoder.yudao.module.contract.enums;
+
+/**
+ * 采购合同状态枚举:0、未归档;1、已归档;2、已完结
+ */
+public enum ContractStatusEnum {
+    /**
+     * 0未归档
+     */
+    UNARCHIVED("0", "未归档"),
+    /**
+     * 1已归档
+     */
+    ARCHIVED("1", "已归档"),
+    /**
+     * 2已完结
+     */
+    END("2", "已完结");
+
+    private final String status;
+    private final String desc;
+
+    ContractStatusEnum(String status, String desc) {
+        this.status = status;
+        this.desc = desc;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+}

+ 18 - 0
yudao-module-finance/yudao-module-contract-api/src/main/java/cn/iocoder/yudao/module/contract/enums/ErrorCodeConstants.java

@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.contract.enums;
+
+import cn.iocoder.yudao.framework.common.exception.ErrorCode;
+
+public interface ErrorCodeConstants {
+    // ========== 采购合同信息 1_052_000_001 ==========
+    ErrorCode SUPPLIER_CONTRACT_NOT_EXISTS = new ErrorCode(1_052_000_001, "采购合同信息不存在");
+    ErrorCode SUPPLIER_CONTRACT_NOT_CLOSED = new ErrorCode(1_052_000_002, "采购合同已经是开启状态");
+    // ========== 采购合同历史信息 1_052_001_001 ==========
+    ErrorCode SUPPLIER_CONTRACT_HISTORY_NOT_EXISTS = new ErrorCode(1_052_001_001, "采购合同历史信息不存在");
+
+    // ========== 销售合同信息 1_052_002_001 ==========
+    ErrorCode CUSTOMER_CONTRACT_NOT_EXISTS = new ErrorCode(1_052_002_001, "销售合同信息不存在");
+    ErrorCode CUSTOMER_CONTRACT_NOT_CLOSED = new ErrorCode(1_052_002_002, "销售合同已经是开启状态");
+    // ========== 销售合同历史信息 1_052_003_001 ==========
+    ErrorCode CUSTOMER_CONTRACT_HISTORY_NOT_EXISTS = new ErrorCode(1_052_003_001, "销售合同历史信息不存在");
+
+}

+ 289 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/customercontract/CustomerContractController.java

@@ -0,0 +1,289 @@
+package cn.iocoder.yudao.module.contract.controller.admin.customercontract;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.enums.GeneralStatusEnum;
+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.module.contract.controller.admin.customercontract.vo.*;
+import cn.iocoder.yudao.module.contract.dal.dataobject.customercontract.CustomerContractDO;
+import cn.iocoder.yudao.module.contract.dal.dataobject.customercontract.CustomerContractHistoryDO;
+import cn.iocoder.yudao.module.contract.enums.ContractStatusEnum;
+import cn.iocoder.yudao.module.contract.service.customercontract.CustomerContractService;
+import cn.iocoder.yudao.module.employee.api.EmployeeApi;
+import cn.iocoder.yudao.module.employee.api.dto.EmployeeRespDTO;
+import cn.iocoder.yudao.module.infra.api.file.FileApi;
+import cn.iocoder.yudao.module.infra.api.file.dto.FileDTO;
+import cn.iocoder.yudao.module.system.api.dept.DeptApi;
+import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springdoc.api.annotations.ParameterObject;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 销售合同信息")
+@RestController
+@RequestMapping("/contract/customer-contract")
+@Validated
+public class CustomerContractController {
+
+    @Resource
+    private CustomerContractService customerContractService;
+
+    @Resource
+    private EmployeeApi employeeApi;
+
+    @Resource
+    private DeptApi deptApi;
+
+    @Resource
+    private FileApi fileApi;
+
+
+    @GetMapping("/getCustomerContractCode")
+    @Operation(summary = "获取销售合同编号")
+    @ApiOperationSupport(order = 1)
+    // @PreAuthorize("@ss.hasPermission('contract:customer-contract:create')")
+    public CommonResult<String> getCustomerContractCode() {
+        return success(customerContractService.getCustomerContractCode());
+    }
+
+
+    @PostMapping("/create")
+    @Operation(summary = "创建销售合同信息")
+    @ApiOperationSupport(order = 2)
+    // @PreAuthorize("@ss.hasPermission('contract:customer-contract:create')")
+    public CommonResult<Long> createCustomerContract(@Valid @RequestBody CustomerContractSaveReqVO createReqVO) {
+        return success(customerContractService.createCustomerContract(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新销售合同信息")
+    @ApiOperationSupport(order = 3)
+    // @PreAuthorize("@ss.hasPermission('contract:customer-contract:update')")
+    public CommonResult<Boolean> updateCustomerContract(@Valid @RequestBody CustomerContractSaveReqVO updateReqVO) {
+        customerContractService.updateCustomerContract(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除销售合同信息")
+    @ApiOperationSupport(order = 4)
+    @Parameter(name = "id", description = "主键id", required = true)
+    // @PreAuthorize("@ss.hasPermission('contract:customer-contract:delete')")
+    public CommonResult<Boolean> deleteCustomerContract(@RequestParam("id") Long id) {
+        customerContractService.deleteCustomerContract(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得销售合同信息")
+    @ApiOperationSupport(order = 5)
+    @Parameter(name = "id", description = "主键id", required = true, example = "1")
+    // @PreAuthorize("@ss.hasPermission('contract:customer-contract:query')")
+    public CommonResult<CustomerContractRespVO> getCustomerContract(@RequestParam("id") Long id) {
+        CustomerContractDO customerContract = customerContractService.getCustomerContract(id);
+        if (Objects.isNull(customerContract)) {
+            return success(null);
+        }
+        CustomerContractRespVO customerContractRespVO = BeanUtils.toBean(customerContract, CustomerContractRespVO.class);
+        // 是否描述集合
+        Map<Integer, String> generalStatusMap = Arrays.stream(GeneralStatusEnum.values())
+                .collect(Collectors.toMap(GeneralStatusEnum::getStatus, GeneralStatusEnum::getName));
+        // 是否框架合同
+        customerContractRespVO.setIsFrameContractDesc(generalStatusMap.getOrDefault(customerContract.getIsFrameContract(), "未知"));
+        // 负责人名称
+        EmployeeRespDTO ownerEmployee = employeeApi.getEmployeeById(customerContract.getOwnerEmployeeId());
+        if (Objects.nonNull(ownerEmployee)) {
+            customerContractRespVO.setOwnerEmployeeName(ownerEmployee.getName());
+        }
+        // 部门名称
+        DeptRespDTO ownerDept = deptApi.getDept(customerContract.getDeptId());
+        if (Objects.nonNull(ownerDept)) {
+            customerContractRespVO.setDeptName(ownerDept.getName());
+        }
+        // 合同状态描述
+        Map<String, String> contractStatusMap = Arrays.stream(ContractStatusEnum.values())
+                .collect(Collectors.toMap(ContractStatusEnum::getStatus, ContractStatusEnum::getDesc));
+        customerContractRespVO.setContractStatusDesc(contractStatusMap.getOrDefault(customerContract.getContractStatus(), "未知"));
+        // 是否关闭
+        customerContractRespVO.setClosedDesc(generalStatusMap.getOrDefault(customerContract.getClosed(), "未知"));
+        // 是否终止
+        customerContractRespVO.setTerminateDesc(generalStatusMap.getOrDefault(customerContract.getTerminate(), "未知"));
+
+        // 附件
+        List<FileDTO> fileDTOList = fileApi.getFileDTOListByBiz(customerContract.getCustomerContractUuid());
+        customerContractRespVO.setFileList(fileDTOList);
+
+        return success(customerContractRespVO);
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得销售合同信息分页")
+    @ApiOperationSupport(order = 6)
+    // @PreAuthorize("@ss.hasPermission('contract:customer-contract:query')")
+    public CommonResult<PageResult<CustomerContractRespVO>> getCustomerContractPage(@Valid @ParameterObject CustomerContractPageReqVO pageReqVO) {
+        PageResult<CustomerContractRespVO> pageResult = customerContractService.getCustomerContractPage(pageReqVO);
+
+        return success(pageResult);
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出销售合同信息 Excel")
+    @ApiOperationSupport(order = 7)
+    // @PreAuthorize("@ss.hasPermission('contract:customer-contract:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportCustomerContractExcel(@ParameterObject CustomerContractPageReqVO pageReqVO,
+                                            HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<CustomerContractRespVO> list = customerContractService.getCustomerContractPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "销售合同信息.xls", "数据", CustomerContractRespVO.class,
+                list);
+    }
+
+    @PutMapping("/open")
+    @Operation(summary = "开启销售合同")
+    @ApiOperationSupport(order = 8)
+    @Parameter(name = "id", description = "主键id", required = true, example = "1")
+    // @PreAuthorize("@ss.hasPermission('contract:customer-contract:update')")
+    public CommonResult<Boolean> openCustomerContract(@RequestParam("id") Long id) {
+        customerContractService.openCustomerContract(id);
+        return success(true);
+    }
+
+    @PutMapping("/close")
+    @Operation(summary = "关闭销售合同")
+    @ApiOperationSupport(order = 9)
+    // @PreAuthorize("@ss.hasPermission('contract:customer-contract:update')")
+    public CommonResult<Boolean> closeCustomerContract(@Valid @RequestBody CustomerContractCloseReqVO closeReqVO) {
+        customerContractService.closeCustomerContract(closeReqVO);
+        return success(true);
+    }
+
+    @PutMapping("/terminate")
+    @Operation(summary = "终止销售合同")
+    @ApiOperationSupport(order = 10)
+    // @PreAuthorize("@ss.hasPermission('contract:customer-contract:update')")
+    public CommonResult<Boolean> terminateCustomerContract(@Valid @RequestBody CustomerContractTerminatedReqVO terminatedReqVO) {
+        customerContractService.terminateCustomerContract(terminatedReqVO);
+        return success(true);
+    }
+
+    @PutMapping("/editCustomerStatus")
+    @Operation(summary = "修改销售合同状态")
+    @ApiOperationSupport(order = 11)
+    // @PreAuthorize("@ss.hasPermission('contract:customer-contract:update')")
+    public CommonResult<Boolean> editCustomerStatus(@Valid @RequestBody CustomerContractStatusReqVO statusReqVO) {
+        customerContractService.editCustomerStatus(statusReqVO);
+        return success(true);
+    }
+
+    @PutMapping("/alter")
+    @Operation(summary = "变更销售合同信息")
+    @ApiOperationSupport(order = 12)
+    // @PreAuthorize("@ss.hasPermission('contract:customer-contract:update')")
+    public CommonResult<Boolean> alterCustomerContract(@Valid @RequestBody CustomerContractSaveReqVO updateReqVO) {
+        customerContractService.alterCustomerContract(updateReqVO);
+        return success(true);
+    }
+
+
+    // ==================== 子表(销售合同历史信息) ====================
+
+    @GetMapping("/customer-contract-history/page")
+    @Operation(summary = "获得销售合同历史信息分页")
+    @ApiOperationSupport(order = 13)
+    @Parameter(name = "code", description = "合同编号,年月日+uuid")
+    // @PreAuthorize("@ss.hasPermission('contract:customer-contract:query')")
+    public CommonResult<PageResult<CustomerContractHistoryDO>> getCustomerContractHistoryPage(PageParam pageReqVO,
+                                                                                              @RequestParam("code") String code) {
+        return success(customerContractService.getCustomerContractHistoryPage(pageReqVO, code));
+    }
+
+    // @PostMapping("/customer-contract-history/create")
+    // @Operation(summary = "创建销售合同历史信息")
+    // @PreAuthorize("@ss.hasPermission('contract:customer-contract:create')")
+    // public CommonResult<Long> createCustomerContractHistory(@Valid @RequestBody CustomerContractHistoryDO customerContractHistory) {
+    //     return success(customerContractService.createCustomerContractHistory(customerContractHistory));
+    // }
+
+    // @PutMapping("/customer-contract-history/update")
+    // @Operation(summary = "更新销售合同历史信息")
+    // @PreAuthorize("@ss.hasPermission('contract:customer-contract:update')")
+    // public CommonResult<Boolean> updateCustomerContractHistory(@Valid @RequestBody CustomerContractHistoryDO customerContractHistory) {
+    //     customerContractService.updateCustomerContractHistory(customerContractHistory);
+    //     return success(true);
+    // }
+
+    // @DeleteMapping("/customer-contract-history/delete")
+    // @Parameter(name = "id", description = "编号", required = true)
+    // @Operation(summary = "删除销售合同历史信息")
+    // @PreAuthorize("@ss.hasPermission('contract:customer-contract:delete')")
+    // public CommonResult<Boolean> deleteCustomerContractHistory(@RequestParam("id") Long id) {
+    //     customerContractService.deleteCustomerContractHistory(id);
+    //     return success(true);
+    // }
+
+    @GetMapping("/customer-contract-history/get")
+    @Operation(summary = "获得销售合同历史信息")
+    @ApiOperationSupport(order = 14)
+    @Parameter(name = "id", description = "主键id", required = true)
+    // @PreAuthorize("@ss.hasPermission('contract:customer-contract:query')")
+    public CommonResult<CustomerContractRespVO> getCustomerContractHistory(@RequestParam("id") Long id) {
+        CustomerContractHistoryDO customerContractHistory = customerContractService.getCustomerContractHistory(id);
+        if (Objects.isNull(customerContractHistory)) {
+            return success(null);
+        }
+        CustomerContractRespVO customerContractRespVO = BeanUtils.toBean(customerContractHistory, CustomerContractRespVO.class);
+
+        // 是否描述集合
+        Map<Integer, String> generalStatusMap = Arrays.stream(GeneralStatusEnum.values())
+                .collect(Collectors.toMap(GeneralStatusEnum::getStatus, GeneralStatusEnum::getName));
+        // 是否框架合同
+        customerContractRespVO.setIsFrameContractDesc(generalStatusMap.getOrDefault(customerContractHistory.getIsFrameContract(), "未知"));
+        // 负责人名称
+        EmployeeRespDTO ownerEmployee = employeeApi.getEmployeeById(customerContractHistory.getOwnerEmployeeId());
+        if (Objects.nonNull(ownerEmployee)) {
+            customerContractRespVO.setOwnerEmployeeName(ownerEmployee.getName());
+        }
+        // 部门名称
+        DeptRespDTO ownerDept = deptApi.getDept(customerContractHistory.getDeptId());
+        if (Objects.nonNull(ownerDept)) {
+            customerContractRespVO.setDeptName(ownerDept.getName());
+        }
+        // 合同状态描述
+        Map<String, String> contractStatusMap = Arrays.stream(ContractStatusEnum.values())
+                .collect(Collectors.toMap(ContractStatusEnum::getStatus, ContractStatusEnum::getDesc));
+        customerContractRespVO.setContractStatusDesc(contractStatusMap.getOrDefault(customerContractHistory.getContractStatus(), "未知"));
+        // 是否关闭
+        customerContractRespVO.setClosedDesc(generalStatusMap.getOrDefault(customerContractHistory.getClosed(), "未知"));
+        // 是否终止
+        customerContractRespVO.setTerminateDesc(generalStatusMap.getOrDefault(customerContractHistory.getTerminate(), "未知"));
+
+        // 附件
+        List<FileDTO> fileDTOList = fileApi.getFileDTOListByBiz(customerContractHistory.getCustomerContractUuid());
+        customerContractRespVO.setFileList(fileDTOList);
+
+        return success(customerContractRespVO);
+    }
+
+}

+ 21 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/customercontract/vo/CustomerContractCloseReqVO.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.contract.controller.admin.customercontract.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 销售合同关闭 Request VO")
+@Data
+public class CustomerContractCloseReqVO {
+
+    @Schema(description = "主键id")
+    @NotNull(message = "主键id不能为空")
+    private Long id;
+
+    @Schema(description = "关闭原因", example = "不喜欢")
+    @NotBlank(message = "关闭原因不能为空")
+    private String closeReason;
+
+}

+ 53 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/customercontract/vo/CustomerContractPageReqVO.java

@@ -0,0 +1,53 @@
+package cn.iocoder.yudao.module.contract.controller.admin.customercontract.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 static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
+
+@Schema(description = "管理后台 - 销售合同信息分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class CustomerContractPageReqVO extends PageParam {
+
+    @Schema(description = "合同编号,年月日+uuid")
+    private String customerContractCode;
+
+    @Schema(description = "合同名称", example = "合同名称")
+    private String customerContractName;
+
+    @Schema(description = "是否为框架合同 0否 1是", example = "0")
+    private Integer isFrameContract;
+
+    @Schema(description = "客户id", example = "客户id")
+    private String customerId;
+
+    @Schema(description = "合同开始日期", example = "2024-08-12,2024-08-12")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
+    private String[] startDate;
+
+    @Schema(description = "合同结束日期", example = "2024-08-12,2024-08-12")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
+    private String[] endDate;
+
+    @Schema(description = "合同负责人", example = "5122")
+    private String ownerEmployeeName;
+
+    @Schema(description = "负责人部门", example = "29650")
+    private Long deptId;
+
+    @Schema(description = "合同状态:0、未归档;1、已归档;2、已完结", example = "2")
+    private String contractStatus;
+
+    @Schema(description = "是否关闭 0开启 1关闭")
+    private Integer closed;
+
+    @Schema(description = "是否终止 0否 1是")
+    private Integer terminate;
+
+}

+ 137 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/customercontract/vo/CustomerContractRespVO.java

@@ -0,0 +1,137 @@
+package cn.iocoder.yudao.module.contract.controller.admin.customercontract.vo;
+
+import cn.iocoder.yudao.module.infra.api.file.dto.FileDTO;
+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.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "管理后台 - 销售合同信息 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class CustomerContractRespVO {
+
+    @Schema(description = "主键id")
+    @ExcelProperty("主键id")
+    private Long id;
+
+    @Schema(description = "合同uuid")
+    @ExcelProperty("合同uuid")
+    private String customerContractUuid;
+
+    @Schema(description = "合同编号,年月日+uuid")
+    @ExcelProperty("合同编号,年月日+uuid")
+    private String customerContractCode;
+
+    @Schema(description = "合同名称")
+    @ExcelProperty("合同名称")
+    private String customerContractName;
+
+    @Schema(description = "是否为框架合同 0否 1是")
+    @ExcelProperty("是否为框架合同 0否 1是")
+    private Integer isFrameContract;
+
+    @Schema(description = "是否为框架合同描述 0否 1是")
+    @ExcelProperty("是否为框架合同描述 0否 1是")
+    private String isFrameContractDesc;
+
+    @Schema(description = "客户id", example = "4213")
+    @ExcelProperty("客户id")
+    private Long customerId;
+
+    @Schema(description = "客户名称", example = "王五")
+    @ExcelProperty("客户名称")
+    private String customerName;
+
+    @Schema(description = "合同开始日期")
+    @ExcelProperty("合同开始日期")
+    private String startDate;
+
+    @Schema(description = "合同结束日期")
+    @ExcelProperty("合同结束日期")
+    private String endDate;
+
+    @Schema(description = "合同金额", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("合同金额")
+    private BigDecimal money;
+
+    @Schema(description = "合同负责人")
+    @ExcelProperty("合同负责人")
+    private Long ownerEmployeeId;
+
+    @Schema(description = "合同负责人")
+    @ExcelProperty("合同负责人")
+    private String ownerEmployeeName;
+
+    @Schema(description = "负责人部门")
+    @ExcelProperty("负责人部门")
+    private Long deptId;
+
+    @Schema(description = "负责人部门名称")
+    @ExcelProperty("负责人部门名称")
+    private String deptName;
+
+    @Schema(description = "合同状态:0、未归档;1、已归档;2、已完结")
+    @ExcelProperty("合同状态:0、未归档;1、已归档;2、已完结")
+    private String contractStatus;
+
+    @Schema(description = "合同状态描述:0、未归档;1、已归档;2、已完结")
+    @ExcelProperty("合同状态描述:0、未归档;1、已归档;2、已完结")
+    private String contractStatusDesc;
+
+    @Schema(description = "是否关闭 0开启 1关闭")
+    @ExcelProperty("是否关闭 0开启 1关闭")
+    private Integer closed;
+
+    @Schema(description = "是否关闭 0开启 1关闭")
+    @ExcelProperty("是否关闭 0开启 1关闭")
+    private String closedDesc;
+
+    @Schema(description = "关闭原因")
+    @ExcelProperty("关闭原因")
+    private String closeReason;
+
+    @Schema(description = "是否终止 0否 1是")
+    @ExcelProperty("是否终止 0否 1是")
+    private Integer terminate;
+
+    @Schema(description = "是否终止 0否 1是")
+    @ExcelProperty("是否终止 0否 1是")
+    private String terminateDesc;
+
+    @Schema(description = "终止日期")
+    @ExcelProperty("终止日期")
+    private String terminateDate;
+
+    @Schema(description = "终止原因")
+    @ExcelProperty("终止原因")
+    private String terminateReason;
+
+    @Schema(description = "是否变更 0否 1是")
+    @ExcelProperty("是否变更 0否 1是")
+    private Integer isChange;
+
+    @Schema(description = "备注")
+    @ExcelProperty("备注")
+    private String remarks;
+
+    @Schema(description = "创建者id")
+    @ExcelProperty("创建者id")
+    private String creator;
+
+    @Schema(description = "创建者名称")
+    @ExcelProperty("创建者名称")
+    private String creatorName;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+    @Schema(description = "附件列表")
+    private List<FileDTO> fileList;
+
+}

+ 66 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/customercontract/vo/CustomerContractSaveReqVO.java

@@ -0,0 +1,66 @@
+package cn.iocoder.yudao.module.contract.controller.admin.customercontract.vo;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.List;
+
+@Schema(description = "管理后台 - 销售合同信息新增/修改 Request VO")
+@Data
+public class CustomerContractSaveReqVO {
+
+
+    @Schema(description = "主键id")
+    private Long id;
+
+    @Schema(description = "合同编号,年月日+uuid", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024080965a74fe2f33c4273803d08d2b5e4aefb")
+    @NotBlank(message = "合同编号不能为空")
+    private String customerContractCode;
+
+    @Schema(description = "合同名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "合同名称不能为空")
+    @NotBlank(message = "合同名称不能为空")
+    private String customerContractName;
+
+    @Schema(description = "是否为框架合同 0否 1是", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+    @NotNull(message = "是否为框架合同 0否 1是不能为空")
+    private Integer isFrameContract;
+
+    @Schema(description = "客户id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @NotNull(message = "客户id不能为空")
+    private Long customerId;
+
+    @Schema(description = "客户名称")
+    private String customerName;
+
+    @Schema(description = "合同开始日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2023-08-09")
+    @NotBlank(message = "合同开始日期不能为空")
+    private String startDate;
+
+    @Schema(description = "合同结束日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2023-08-09")
+    @NotBlank(message = "合同结束日期不能为空")
+    private String endDate;
+
+    @Schema(description = "合同金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "10.00")
+    @NotNull(message = "合同金额不能为空")
+    @Min(value = 0, message = "合同金额不能小于0")
+    private BigDecimal money;
+
+    @Schema(description = "合同负责人", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    private Long ownerEmployeeId;
+
+    @Schema(description = "备注", example = "备注可以为空")
+    private String remarks;
+
+    @Schema(description = "附件主键id", example = "[]")
+    private List<Long> fileIdList;
+
+    @Schema(description = "是否变更 0否 1是,无需传递该参数", example = "0")
+    @JsonIgnore
+    private Integer isChange;
+
+}

+ 21 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/customercontract/vo/CustomerContractStatusReqVO.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.contract.controller.admin.customercontract.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 销售合同修改状态 Request VO")
+@Data
+public class CustomerContractStatusReqVO {
+
+    @Schema(description = "主键id")
+    @NotNull(message = "主键id不能为空")
+    private Long id;
+
+    @Schema(description = "合同状态:0、未归档;1、已归档;2、已完结", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    @NotBlank(message = "合同状态:0、未归档;1、已归档;2、已完结不能为空")
+    private String contractStatus;
+
+}

+ 25 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/customercontract/vo/CustomerContractTerminatedReqVO.java

@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.contract.controller.admin.customercontract.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 销售合同终止 Request VO")
+@Data
+public class CustomerContractTerminatedReqVO {
+
+    @Schema(description = "主键id")
+    @NotNull(message = "主键id不能为空")
+    private Long id;
+
+    @Schema(description = "终止日期")
+    @NotBlank(message = "终止日期不能为空")
+    private String terminateDate;
+
+    @Schema(description = "终止原因", example = "不对")
+    @NotBlank(message = "终止原因不能为空")
+    private String terminateReason;
+
+}

+ 287 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/suppliercontract/SupplierContractController.java

@@ -0,0 +1,287 @@
+package cn.iocoder.yudao.module.contract.controller.admin.suppliercontract;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.enums.GeneralStatusEnum;
+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.module.contract.controller.admin.suppliercontract.vo.*;
+import cn.iocoder.yudao.module.contract.dal.dataobject.suppliercontract.SupplierContractDO;
+import cn.iocoder.yudao.module.contract.dal.dataobject.suppliercontract.SupplierContractHistoryDO;
+import cn.iocoder.yudao.module.contract.enums.ContractStatusEnum;
+import cn.iocoder.yudao.module.contract.service.suppliercontract.SupplierContractService;
+import cn.iocoder.yudao.module.employee.api.EmployeeApi;
+import cn.iocoder.yudao.module.employee.api.dto.EmployeeRespDTO;
+import cn.iocoder.yudao.module.infra.api.file.FileApi;
+import cn.iocoder.yudao.module.infra.api.file.dto.FileDTO;
+import cn.iocoder.yudao.module.system.api.dept.DeptApi;
+import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springdoc.api.annotations.ParameterObject;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 采购合同信息")
+@RestController
+@RequestMapping("/finance/contract/supplier-contract")
+@Validated
+public class SupplierContractController {
+
+    @Resource
+    private SupplierContractService supplierContractService;
+
+    @Resource
+    private EmployeeApi employeeApi;
+
+    @Resource
+    private DeptApi deptApi;
+
+    @Resource
+    private FileApi fileApi;
+
+    @GetMapping("/getSupplierContractCode")
+    @Operation(summary = "获取采购合同编号")
+    @ApiOperationSupport(order = 1)
+    // @PreAuthorize("@ss.hasPermission('contract:supplier-contract:create')")
+    public CommonResult<String> getSupplierContractCode() {
+        return success(supplierContractService.getSupplierContractCode());
+    }
+
+    @PostMapping("/create")
+    @Operation(summary = "创建采购合同信息")
+    @ApiOperationSupport(order = 2)
+    // @PreAuthorize("@ss.hasPermission('contract:supplier-contract:create')")
+    public CommonResult<Long> createSupplierContract(@Valid @RequestBody SupplierContractSaveReqVO createReqVO) {
+        return success(supplierContractService.createSupplierContract(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新采购合同信息")
+    @ApiOperationSupport(order = 3)
+    // @PreAuthorize("@ss.hasPermission('contract:supplier-contract:update')")
+    public CommonResult<Boolean> updateSupplierContract(@Valid @RequestBody SupplierContractSaveReqVO updateReqVO) {
+        supplierContractService.updateSupplierContract(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除采购合同信息")
+    @ApiOperationSupport(order = 4)
+    @Parameter(name = "id", description = "主键id", required = true)
+    // @PreAuthorize("@ss.hasPermission('contract:supplier-contract:delete')")
+    public CommonResult<Boolean> deleteSupplierContract(@RequestParam("id") Long id) {
+        supplierContractService.deleteSupplierContract(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得采购合同信息")
+    @ApiOperationSupport(order = 5)
+    @Parameter(name = "id", description = "主键id", required = true, example = "1")
+    // @PreAuthorize("@ss.hasPermission('contract:supplier-contract:query')")
+    public CommonResult<SupplierContractRespVO> getSupplierContract(@RequestParam("id") Long id) {
+        SupplierContractDO supplierContract = supplierContractService.getSupplierContract(id);
+        if (Objects.isNull(supplierContract)) {
+            return success(null);
+        }
+        SupplierContractRespVO supplierContractRespVO = BeanUtils.toBean(supplierContract, SupplierContractRespVO.class);
+        // 是否描述集合
+        Map<Integer, String> generalStatusMap = Arrays.stream(GeneralStatusEnum.values())
+                .collect(Collectors.toMap(GeneralStatusEnum::getStatus, GeneralStatusEnum::getName));
+        // 是否框架合同
+        supplierContractRespVO.setIsFrameContractDesc(generalStatusMap.getOrDefault(supplierContract.getIsFrameContract(), "未知"));
+        // 负责人名称
+        EmployeeRespDTO ownerEmployee = employeeApi.getEmployeeById(supplierContract.getOwnerEmployeeId());
+        if (Objects.nonNull(ownerEmployee)) {
+            supplierContractRespVO.setOwnerEmployeeName(ownerEmployee.getName());
+        }
+        // 部门名称
+        DeptRespDTO ownerDept = deptApi.getDept(supplierContract.getDeptId());
+        if (Objects.nonNull(ownerDept)) {
+            supplierContractRespVO.setDeptName(ownerDept.getName());
+        }
+        // 合同状态描述
+        Map<String, String> contractStatusMap = Arrays.stream(ContractStatusEnum.values())
+                .collect(Collectors.toMap(ContractStatusEnum::getStatus, ContractStatusEnum::getDesc));
+        supplierContractRespVO.setContractStatusDesc(contractStatusMap.getOrDefault(supplierContract.getContractStatus(), "未知"));
+        // 是否关闭
+        supplierContractRespVO.setClosedDesc(generalStatusMap.getOrDefault(supplierContract.getClosed(), "未知"));
+        // 是否终止
+        supplierContractRespVO.setTerminateDesc(generalStatusMap.getOrDefault(supplierContract.getTerminate(), "未知"));
+
+        // 附件
+        List<FileDTO> fileDTOList = fileApi.getFileDTOListByBiz(supplierContract.getSupplierContractUuid());
+        supplierContractRespVO.setFileList(fileDTOList);
+
+        return success(supplierContractRespVO);
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得采购合同信息分页")
+    @ApiOperationSupport(order = 6)
+    // @PreAuthorize("@ss.hasPermission('contract:supplier-contract:query')")
+    public CommonResult<PageResult<SupplierContractRespVO>> getSupplierContractPage(@Valid @ParameterObject SupplierContractPageReqVO pageReqVO) {
+        PageResult<SupplierContractRespVO> pageResult = supplierContractService.getSupplierContractPage(pageReqVO);
+
+        return success(pageResult);
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出采购合同信息 Excel")
+    @ApiOperationSupport(order = 7)
+    // @PreAuthorize("@ss.hasPermission('contract:supplier-contract:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportSupplierContractExcel(@ParameterObject SupplierContractPageReqVO pageReqVO,
+                                            HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<SupplierContractRespVO> list = supplierContractService.getSupplierContractPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "采购合同信息.xls", "数据", SupplierContractRespVO.class,
+                list);
+    }
+
+    @PutMapping("/open")
+    @Operation(summary = "开启采购合同")
+    @ApiOperationSupport(order = 8)
+    @Parameter(name = "id", description = "主键id", required = true, example = "1")
+    // @PreAuthorize("@ss.hasPermission('contract:supplier-contract:update')")
+    public CommonResult<Boolean> openSupplierContract(@RequestParam("id") Long id) {
+        supplierContractService.openSupplierContract(id);
+        return success(true);
+    }
+
+    @PutMapping("/close")
+    @Operation(summary = "关闭采购合同")
+    @ApiOperationSupport(order = 9)
+    // @PreAuthorize("@ss.hasPermission('contract:supplier-contract:update')")
+    public CommonResult<Boolean> closeSupplierContract(@Valid @RequestBody SupplierContractCloseReqVO closeReqVO) {
+        supplierContractService.closeSupplierContract(closeReqVO);
+        return success(true);
+    }
+
+    @PutMapping("/terminate")
+    @Operation(summary = "终止采购合同")
+    @ApiOperationSupport(order = 10)
+    // @PreAuthorize("@ss.hasPermission('contract:supplier-contract:update')")
+    public CommonResult<Boolean> terminateSupplierContract(@Valid @RequestBody SupplierContractTerminatedReqVO terminatedReqVO) {
+        supplierContractService.terminateSupplierContract(terminatedReqVO);
+        return success(true);
+    }
+
+    @PutMapping("/editSupplierStatus")
+    @Operation(summary = "修改采购合同状态")
+    @ApiOperationSupport(order = 11)
+    // @PreAuthorize("@ss.hasPermission('contract:supplier-contract:update')")
+    public CommonResult<Boolean> editSupplierStatus(@Valid @RequestBody SupplierContractStatusReqVO statusReqVO) {
+        supplierContractService.editSupplierStatus(statusReqVO);
+        return success(true);
+    }
+
+    @PutMapping("/alter")
+    @Operation(summary = "变更采购合同信息")
+    @ApiOperationSupport(order = 12)
+    // @PreAuthorize("@ss.hasPermission('contract:supplier-contract:update')")
+    public CommonResult<Boolean> alterSupplierContract(@Valid @RequestBody SupplierContractSaveReqVO updateReqVO) {
+        supplierContractService.alterSupplierContract(updateReqVO);
+        return success(true);
+    }
+
+
+    // ==================== 子表(采购合同历史信息) ====================
+
+    @GetMapping("/supplier-contract-history/page")
+    @Operation(summary = "获得采购合同历史信息分页")
+    @ApiOperationSupport(order = 13)
+    @Parameter(name = "code", description = "合同编号,年月日+uuid")
+    // @PreAuthorize("@ss.hasPermission('contract:supplier-contract:query')")
+    public CommonResult<PageResult<SupplierContractHistoryDO>> getSupplierContractHistoryPage(PageParam pageReqVO,
+                                                                                              @RequestParam("code") String code) {
+        return success(supplierContractService.getSupplierContractHistoryPage(pageReqVO, code));
+    }
+
+    // @PostMapping("/supplier-contract-history/create")
+    // @Operation(summary = "创建采购合同历史信息")
+    // @PreAuthorize("@ss.hasPermission('contract:supplier-contract:create')")
+    // public CommonResult<Long> createSupplierContractHistory(@Valid @RequestBody SupplierContractHistoryDO supplierContractHistory) {
+    //     return success(supplierContractService.createSupplierContractHistory(supplierContractHistory));
+    // }
+
+    // @PutMapping("/supplier-contract-history/update")
+    // @Operation(summary = "更新采购合同历史信息")
+    // @PreAuthorize("@ss.hasPermission('contract:supplier-contract:update')")
+    // public CommonResult<Boolean> updateSupplierContractHistory(@Valid @RequestBody SupplierContractHistoryDO supplierContractHistory) {
+    //     supplierContractService.updateSupplierContractHistory(supplierContractHistory);
+    //     return success(true);
+    // }
+
+    // @DeleteMapping("/supplier-contract-history/delete")
+    // @Parameter(name = "id", description = "编号", required = true)
+    // @Operation(summary = "删除采购合同历史信息")
+    // @PreAuthorize("@ss.hasPermission('contract:supplier-contract:delete')")
+    // public CommonResult<Boolean> deleteSupplierContractHistory(@RequestParam("id") Long id) {
+    //     supplierContractService.deleteSupplierContractHistory(id);
+    //     return success(true);
+    // }
+
+	@GetMapping("/supplier-contract-history/get")
+	@Operation(summary = "获得采购合同历史信息")
+    @ApiOperationSupport(order = 14)
+	@Parameter(name = "id", description = "主键id", required = true)
+    // @PreAuthorize("@ss.hasPermission('contract:supplier-contract:query')")
+	public CommonResult<SupplierContractRespVO> getSupplierContractHistory(@RequestParam("id") Long id) {
+        SupplierContractHistoryDO supplierContractHistory = supplierContractService.getSupplierContractHistory(id);
+        if (Objects.isNull(supplierContractHistory)) {
+            return CommonResult.success(null);
+        }
+        SupplierContractRespVO supplierContractRespVO = BeanUtils.toBean(supplierContractHistory, SupplierContractRespVO.class);
+
+        // 是否描述集合
+        Map<Integer, String> generalStatusMap = Arrays.stream(GeneralStatusEnum.values())
+                .collect(Collectors.toMap(GeneralStatusEnum::getStatus, GeneralStatusEnum::getName));
+        // 是否框架合同
+        supplierContractRespVO.setIsFrameContractDesc(generalStatusMap.getOrDefault(supplierContractHistory.getIsFrameContract(), "未知"));
+        // 负责人名称
+        EmployeeRespDTO ownerEmployee = employeeApi.getEmployeeById(supplierContractHistory.getOwnerEmployeeId());
+        if (Objects.nonNull(ownerEmployee)) {
+            supplierContractRespVO.setOwnerEmployeeName(ownerEmployee.getName());
+        }
+        // 部门名称
+        DeptRespDTO ownerDept = deptApi.getDept(supplierContractHistory.getDeptId());
+        if (Objects.nonNull(ownerDept)) {
+            supplierContractRespVO.setDeptName(ownerDept.getName());
+        }
+        // 合同状态描述
+        Map<String, String> contractStatusMap = Arrays.stream(ContractStatusEnum.values())
+                .collect(Collectors.toMap(ContractStatusEnum::getStatus, ContractStatusEnum::getDesc));
+        supplierContractRespVO.setContractStatusDesc(contractStatusMap.getOrDefault(supplierContractHistory.getContractStatus(), "未知"));
+        // 是否关闭
+        supplierContractRespVO.setClosedDesc(generalStatusMap.getOrDefault(supplierContractHistory.getClosed(), "未知"));
+        // 是否终止
+        supplierContractRespVO.setTerminateDesc(generalStatusMap.getOrDefault(supplierContractHistory.getTerminate(), "未知"));
+
+        // 附件
+        List<FileDTO> fileDTOList = fileApi.getFileDTOListByBiz(supplierContractHistory.getSupplierContractUuid());
+        supplierContractRespVO.setFileList(fileDTOList);
+
+        return success(supplierContractRespVO);
+	}
+
+}

+ 21 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/suppliercontract/vo/SupplierContractCloseReqVO.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.contract.controller.admin.suppliercontract.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 采购合同关闭 Request VO")
+@Data
+public class SupplierContractCloseReqVO {
+
+    @Schema(description = "主键id")
+    @NotNull(message = "主键id不能为空")
+    private Long id;
+
+    @Schema(description = "关闭原因", example = "不喜欢")
+    @NotBlank(message = "关闭原因不能为空")
+    private String closeReason;
+
+}

+ 52 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/suppliercontract/vo/SupplierContractPageReqVO.java

@@ -0,0 +1,52 @@
+package cn.iocoder.yudao.module.contract.controller.admin.suppliercontract.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 static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
+
+@Schema(description = "管理后台 - 采购合同信息分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class SupplierContractPageReqVO extends PageParam {
+
+    @Schema(description = "合同编号,年月日+uuid")
+    private String supplierContractCode;
+
+    @Schema(description = "合同名称", example = "合同名称")
+    private String supplierContractName;
+
+    @Schema(description = "是否为框架合同 0否 1是", example = "0")
+    private Integer isFrameContract;
+
+    @Schema(description = "供应商名称", example = "供应商名称")
+    private String supplierName;
+
+    @Schema(description = "合同开始日期", example = "2024-08-12,2024-08-12")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
+    private String[] startDate;
+
+    @Schema(description = "合同结束日期", example = "2024-08-12,2024-08-12")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
+    private String[] endDate;
+
+    @Schema(description = "合同负责人", example = "5122")
+    private String ownerEmployeeName;
+
+    @Schema(description = "负责人部门", example = "29650")
+    private Long deptId;
+
+    @Schema(description = "合同状态:0、未归档;1、已归档;2、已完结", example = "2")
+    private String contractStatus;
+
+    @Schema(description = "是否关闭 0开启 1关闭")
+    private Integer closed;
+
+    @Schema(description = "是否终止 0否 1是")
+    private Integer terminate;
+}

+ 136 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/suppliercontract/vo/SupplierContractRespVO.java

@@ -0,0 +1,136 @@
+package cn.iocoder.yudao.module.contract.controller.admin.suppliercontract.vo;
+
+import cn.iocoder.yudao.module.infra.api.file.dto.FileDTO;
+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.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "管理后台 - 采购合同信息 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class SupplierContractRespVO {
+
+    @Schema(description = "主键id")
+    @ExcelProperty("主键id")
+    private Long id;
+
+    @Schema(description = "合同uuid")
+    @ExcelProperty("合同uuid")
+    private String supplierContractUuid;
+
+    @Schema(description = "合同编号,年月日+uuid")
+    @ExcelProperty("合同编号,年月日+uuid")
+    private String supplierContractCode;
+
+    @Schema(description = "合同名称")
+    @ExcelProperty("合同名称")
+    private String supplierContractName;
+
+    @Schema(description = "是否为框架合同 0否 1是")
+    @ExcelProperty("是否为框架合同 0否 1是")
+    private Integer isFrameContract;
+
+    @Schema(description = "是否为框架合同描述 0否 1是")
+    @ExcelProperty("是否为框架合同描述 0否 1是")
+    private String isFrameContractDesc;
+
+    @Schema(description = "供应商id", example = "4213")
+    @ExcelProperty("供应商id")
+    private Long supplierId;
+
+    @Schema(description = "供应商名称", example = "王五")
+    @ExcelProperty("供应商名称")
+    private String supplierName;
+
+    @Schema(description = "合同开始日期")
+    @ExcelProperty("合同开始日期")
+    private String startDate;
+
+    @Schema(description = "合同结束日期")
+    @ExcelProperty("合同结束日期")
+    private String endDate;
+
+    @Schema(description = "合同金额", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("合同金额")
+    private BigDecimal money;
+
+    @Schema(description = "合同负责人")
+    @ExcelProperty("合同负责人")
+    private Long ownerEmployeeId;
+
+    @Schema(description = "合同负责人")
+    @ExcelProperty("合同负责人")
+    private String ownerEmployeeName;
+
+    @Schema(description = "负责人部门")
+    @ExcelProperty("负责人部门")
+    private Long deptId;
+
+    @Schema(description = "负责人部门名称")
+    @ExcelProperty("负责人部门名称")
+    private String deptName;
+
+    @Schema(description = "合同状态:0、未归档;1、已归档;2、已完结")
+    @ExcelProperty("合同状态:0、未归档;1、已归档;2、已完结")
+    private String contractStatus;
+
+    @Schema(description = "合同状态描述:0、未归档;1、已归档;2、已完结")
+    @ExcelProperty("合同状态描述:0、未归档;1、已归档;2、已完结")
+    private String contractStatusDesc;
+
+    @Schema(description = "是否关闭 0开启 1关闭")
+    @ExcelProperty("是否关闭 0开启 1关闭")
+    private Integer closed;
+
+    @Schema(description = "是否关闭 0开启 1关闭")
+    @ExcelProperty("是否关闭 0开启 1关闭")
+    private String closedDesc;
+
+    @Schema(description = "关闭原因")
+    @ExcelProperty("关闭原因")
+    private String closeReason;
+
+    @Schema(description = "是否终止 0否 1是")
+    @ExcelProperty("是否终止 0否 1是")
+    private Integer terminate;
+
+    @Schema(description = "是否终止 0否 1是")
+    @ExcelProperty("是否终止 0否 1是")
+    private String terminateDesc;
+
+    @Schema(description = "终止日期")
+    @ExcelProperty("终止日期")
+    private String terminateDate;
+
+    @Schema(description = "终止原因")
+    @ExcelProperty("终止原因")
+    private String terminateReason;
+
+    @Schema(description = "是否变更 0否 1是")
+    @ExcelProperty("是否变更 0否 1是")
+    private Integer isChange;
+
+    @Schema(description = "备注")
+    @ExcelProperty("备注")
+    private String remarks;
+
+    @Schema(description = "创建者id")
+    @ExcelProperty("创建者id")
+    private String creator;
+
+    @Schema(description = "创建者名称")
+    @ExcelProperty("创建者名称")
+    private String creatorName;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+    @Schema(description = "附件列表")
+    private List<FileDTO> fileList;
+}

+ 64 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/suppliercontract/vo/SupplierContractSaveReqVO.java

@@ -0,0 +1,64 @@
+package cn.iocoder.yudao.module.contract.controller.admin.suppliercontract.vo;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.List;
+
+@Schema(description = "管理后台 - 采购合同信息新增/修改 Request VO")
+@Data
+public class SupplierContractSaveReqVO {
+
+    @Schema(description = "主键id")
+    private Long id;
+
+    @Schema(description = "合同编号,年月日+uuid", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024080965a74fe2f33c4273803d08d2b5e4aefb")
+    @NotBlank(message = "合同编号不能为空")
+    private String supplierContractCode;
+
+    @Schema(description = "合同名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "合同名称不能为空")
+    @NotBlank(message = "合同名称不能为空")
+    private String supplierContractName;
+
+    @Schema(description = "是否为框架合同 0否 1是", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+    @NotNull(message = "是否为框架合同 0否 1是不能为空")
+    private Integer isFrameContract;
+
+    @Schema(description = "供应商id")
+    private Long supplierId;
+
+    @Schema(description = "供应商名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "供应商名称不能为空")
+    @NotBlank(message = "供应商名称不能为空")
+    private String supplierName;
+
+    @Schema(description = "合同开始日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2023-08-09")
+    @NotBlank(message = "合同开始日期不能为空")
+    private String startDate;
+
+    @Schema(description = "合同结束日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2023-08-09")
+    @NotBlank(message = "合同结束日期不能为空")
+    private String endDate;
+
+    @Schema(description = "合同金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "10.00")
+    @NotNull(message = "合同金额不能为空")
+    @Min(value = 0, message = "合同金额不能小于0")
+    private BigDecimal money;
+
+    @Schema(description = "合同负责人", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    private Long ownerEmployeeId;
+
+    @Schema(description = "备注", example = "备注可以为空")
+    private String remarks;
+
+    @Schema(description = "附件主键id", example = "[]")
+    private List<Long> fileIdList;
+
+    @Schema(description = "是否变更 0否 1是,无需传递该参数", example = "0")
+    @JsonIgnore
+    private Integer isChange;
+}

+ 21 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/suppliercontract/vo/SupplierContractStatusReqVO.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.contract.controller.admin.suppliercontract.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 采购合同修改状态 Request VO")
+@Data
+public class SupplierContractStatusReqVO {
+
+    @Schema(description = "主键id")
+    @NotNull(message = "主键id不能为空")
+    private Long id;
+
+    @Schema(description = "合同状态:0、未归档;1、已归档;2、已完结", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    @NotBlank(message = "合同状态:0、未归档;1、已归档;2、已完结不能为空")
+    private String contractStatus;
+
+}

+ 25 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/controller/admin/suppliercontract/vo/SupplierContractTerminatedReqVO.java

@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.contract.controller.admin.suppliercontract.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 采购合同终止 Request VO")
+@Data
+public class SupplierContractTerminatedReqVO {
+
+    @Schema(description = "主键id")
+    @NotNull(message = "主键id不能为空")
+    private Long id;
+
+    @Schema(description = "终止日期")
+    @NotBlank(message = "终止日期不能为空")
+    private String terminateDate;
+
+    @Schema(description = "终止原因", example = "不对")
+    @NotBlank(message = "终止原因不能为空")
+    private String terminateReason;
+
+}

+ 108 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/dal/dataobject/customercontract/CustomerContractDO.java

@@ -0,0 +1,108 @@
+package cn.iocoder.yudao.module.contract.dal.dataobject.customercontract;
+
+import lombok.*;
+import java.util.*;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 销售合同信息 DO
+ *
+ * @author dp
+ */
+@TableName("finance_customer_contract")
+@KeySequence("finance_customer_contract_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class CustomerContractDO extends BaseDO {
+
+    /**
+     * 主键id
+     */
+    @TableId
+    private Long id;
+    /**
+     * uuid
+     */
+    private String customerContractUuid;
+    /**
+     * 合同编号,年月日+uuid
+     */
+    private String customerContractCode;
+    /**
+     * 合同名称
+     */
+    private String customerContractName;
+    /**
+     * 是否为框架合同 0否 1是
+     */
+    private Integer isFrameContract;
+    /**
+     * 客户id
+     */
+    private Long customerId;
+    /**
+     * 客户名称
+     */
+    private String customerName;
+    /**
+     * 合同开始日期
+     */
+    private String startDate;
+    /**
+     * 合同结束日期
+     */
+    private String endDate;
+    /**
+     * 合同金额
+     */
+    private BigDecimal money;
+    /**
+     * 合同负责人
+     */
+    private Long ownerEmployeeId;
+    /**
+     * 负责人部门
+     */
+    private Long deptId;
+    /**
+     * 合同状态:0、未归档;1、已归档;2、已完结
+     */
+    private String contractStatus;
+    /**
+     * 是否关闭 0开启 1关闭
+     */
+    private Integer closed;
+    /**
+     * 关闭原因
+     */
+    private String closeReason;
+    /**
+     * 是否终止 0否 1是
+     */
+    private Integer terminate;
+    /**
+     * 终止日期
+     */
+    private String terminateDate;
+    /**
+     * 终止原因
+     */
+    private String terminateReason;
+    /**
+     * 是否变更 0否 1是
+     */
+    private Integer isChange;
+    /**
+     * 备注
+     */
+    private String remarks;
+
+}

+ 108 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/dal/dataobject/customercontract/CustomerContractHistoryDO.java

@@ -0,0 +1,108 @@
+package cn.iocoder.yudao.module.contract.dal.dataobject.customercontract;
+
+import lombok.*;
+import java.util.*;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 销售合同历史信息 DO
+ *
+ * @author dp
+ */
+@TableName("finance_customer_contract_history")
+@KeySequence("finance_customer_contract_history_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class CustomerContractHistoryDO extends BaseDO {
+
+    /**
+     * 主键id
+     */
+    @TableId
+    private Long id;
+    /**
+     * uuid
+     */
+    private String customerContractUuid;
+    /**
+     * 合同编号,年月日+uuid
+     */
+    private String customerContractCode;
+    /**
+     * 合同名称
+     */
+    private String customerContractName;
+    /**
+     * 是否为框架合同 0否 1是
+     */
+    private Integer isFrameContract;
+    /**
+     * 客户id
+     */
+    private Long customerId;
+    /**
+     * 客户名称
+     */
+    private String customerName;
+    /**
+     * 合同开始日期
+     */
+    private String startDate;
+    /**
+     * 合同结束日期
+     */
+    private String endDate;
+    /**
+     * 合同金额
+     */
+    private BigDecimal money;
+    /**
+     * 合同负责人
+     */
+    private Long ownerEmployeeId;
+    /**
+     * 负责人部门
+     */
+    private Long deptId;
+    /**
+     * 合同状态:0、未归档;1、已归档;2、已完结
+     */
+    private String contractStatus;
+    /**
+     * 是否关闭 0开启 1关闭
+     */
+    private Integer closed;
+    /**
+     * 关闭原因
+     */
+    private String closeReason;
+    /**
+     * 是否终止 0否 1是
+     */
+    private Integer terminate;
+    /**
+     * 终止日期
+     */
+    private String terminateDate;
+    /**
+     * 终止原因
+     */
+    private String terminateReason;
+    /**
+     * 是否变更 0否 1是
+     */
+    private Integer isChange;
+    /**
+     * 备注
+     */
+    private String remarks;
+
+}

+ 108 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/dal/dataobject/suppliercontract/SupplierContractDO.java

@@ -0,0 +1,108 @@
+package cn.iocoder.yudao.module.contract.dal.dataobject.suppliercontract;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.math.BigDecimal;
+
+/**
+ * 采购合同信息 DO
+ *
+ * @author dp
+ */
+@TableName("finance_supplier_contract")
+@KeySequence("finance_supplier_contract_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class SupplierContractDO extends BaseDO {
+
+    /**
+     * 主键id
+     */
+    @TableId
+    private Long id;
+    /**
+     * uuid
+     */
+    private String supplierContractUuid;
+    /**
+     * 合同编号,年月日+uuid
+     */
+    private String supplierContractCode;
+    /**
+     * 合同名称
+     */
+    private String supplierContractName;
+    /**
+     * 是否为框架合同 0否 1是
+     */
+    private Integer isFrameContract;
+    /**
+     * 供应商id
+     */
+    private Long supplierId;
+    /**
+     * 供应商名称
+     */
+    private String supplierName;
+    /**
+     * 合同开始日期
+     */
+    private String startDate;
+    /**
+     * 合同结束日期
+     */
+    private String endDate;
+    /**
+     * 合同金额
+     */
+    private BigDecimal money;
+    /**
+     * 合同负责人
+     */
+    private Long ownerEmployeeId;
+    /**
+     * 负责人部门
+     */
+    private Long deptId;
+    /**
+     * 合同状态:0、未归档;1、已归档;2、已完结
+     */
+    private String contractStatus;
+    /**
+     * 是否关闭 0开启 1关闭
+     */
+    private Integer closed;
+    /**
+     * 关闭原因
+     */
+    private String closeReason;
+    /**
+     * 是否终止 0否 1是
+     */
+    private Integer terminate;
+    /**
+     * 终止日期
+     */
+    private String terminateDate;
+    /**
+     * 终止原因
+     */
+    private String terminateReason;
+    /**
+     * 是否变更 0否 1是
+     */
+    private Integer isChange;
+    /**
+     * 备注
+     */
+    private String remarks;
+
+}

+ 108 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/dal/dataobject/suppliercontract/SupplierContractHistoryDO.java

@@ -0,0 +1,108 @@
+package cn.iocoder.yudao.module.contract.dal.dataobject.suppliercontract;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.math.BigDecimal;
+
+/**
+ * 采购合同历史信息 DO
+ *
+ * @author dp
+ */
+@TableName("finance_supplier_contract_history")
+@KeySequence("finance_supplier_contract_history_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class SupplierContractHistoryDO extends BaseDO {
+
+    /**
+     * 主键id
+     */
+    @TableId
+    private Long id;
+    /**
+     * uuid
+     */
+    private String supplierContractUuid;
+    /**
+     * 合同编号,年月日+uuid
+     */
+    private String supplierContractCode;
+    /**
+     * 合同名称
+     */
+    private String supplierContractName;
+    /**
+     * 是否为框架合同 0否 1是
+     */
+    private Integer isFrameContract;
+    /**
+     * 供应商id
+     */
+    private Long supplierId;
+    /**
+     * 供应商名称
+     */
+    private String supplierName;
+    /**
+     * 合同开始日期
+     */
+    private String startDate;
+    /**
+     * 合同结束日期
+     */
+    private String endDate;
+    /**
+     * 合同金额
+     */
+    private BigDecimal money;
+    /**
+     * 合同负责人
+     */
+    private Long ownerEmployeeId;
+    /**
+     * 负责人部门
+     */
+    private Long deptId;
+    /**
+     * 合同状态:0、未归档;1、已归档;2、已完结
+     */
+    private String contractStatus;
+    /**
+     * 是否关闭 0开启 1关闭
+     */
+    private Integer closed;
+    /**
+     * 关闭原因
+     */
+    private String closeReason;
+    /**
+     * 是否终止 0否 1是
+     */
+    private Integer terminate;
+    /**
+     * 终止日期
+     */
+    private String terminateDate;
+    /**
+     * 终止原因
+     */
+    private String terminateReason;
+    /**
+     * 是否变更 0否 1是
+     */
+    private Integer isChange;
+    /**
+     * 备注
+     */
+    private String remarks;
+
+}

+ 35 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/dal/mysql/customercontract/CustomerContractHistoryMapper.java

@@ -0,0 +1,35 @@
+package cn.iocoder.yudao.module.contract.dal.mysql.customercontract;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+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.contract.dal.dataobject.customercontract.CustomerContractHistoryDO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 销售合同历史信息 Mapper
+ *
+ * @author dp
+ */
+@Mapper
+public interface CustomerContractHistoryMapper extends BaseMapperX<CustomerContractHistoryDO> {
+
+    default PageResult<CustomerContractHistoryDO> selectPage(PageParam reqVO, String customerContractCode) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<CustomerContractHistoryDO>()
+            .eq(CustomerContractHistoryDO::getCustomerContractCode, customerContractCode)
+            .orderByDesc(CustomerContractHistoryDO::getId));
+    }
+
+    default int deleteByCode(String code) {
+        return delete(CustomerContractHistoryDO::getCustomerContractCode, code);
+    }
+
+    long getPageCount(@Param("page") PageParam pageReqVO, @Param("code") String code);
+
+    List<CustomerContractHistoryDO> getPageList(@Param("page") PageParam pageReqVO, @Param("code") String code);
+
+}

+ 62 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/dal/mysql/customercontract/CustomerContractMapper.java

@@ -0,0 +1,62 @@
+package cn.iocoder.yudao.module.contract.dal.mysql.customercontract;
+
+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.contract.controller.admin.customercontract.vo.CustomerContractPageReqVO;
+import cn.iocoder.yudao.module.contract.controller.admin.customercontract.vo.CustomerContractRespVO;
+import cn.iocoder.yudao.module.contract.dal.dataobject.customercontract.CustomerContractDO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 销售合同信息 Mapper
+ *
+ * @author dp
+ */
+@Mapper
+public interface CustomerContractMapper extends BaseMapperX<CustomerContractDO> {
+
+    default PageResult<CustomerContractDO> selectPage(CustomerContractPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<CustomerContractDO>()
+                .eqIfPresent(CustomerContractDO::getCustomerContractCode, reqVO.getCustomerContractCode())
+                .likeIfPresent(CustomerContractDO::getCustomerContractName, reqVO.getCustomerContractName())
+                .eqIfPresent(CustomerContractDO::getIsFrameContract, reqVO.getIsFrameContract())
+                .eqIfPresent(CustomerContractDO::getCustomerId, reqVO.getCustomerId())
+                .betweenIfPresent(CustomerContractDO::getStartDate, reqVO.getStartDate())
+                .betweenIfPresent(CustomerContractDO::getEndDate, reqVO.getEndDate())
+                .eqIfPresent(CustomerContractDO::getDeptId, reqVO.getDeptId())
+                .eqIfPresent(CustomerContractDO::getContractStatus, reqVO.getContractStatus())
+                .eqIfPresent(CustomerContractDO::getClosed, reqVO.getClosed())
+                .eqIfPresent(CustomerContractDO::getTerminate, reqVO.getTerminate())
+                .orderByDesc(CustomerContractDO::getId));
+    }
+
+
+    /**
+     * 获取销售合同信息总数量
+     *
+     * @param pageReqVO 分页参数
+     * @return 销售合同信息分页总数量
+     */
+    long getPageCount(@Param("page") CustomerContractPageReqVO pageReqVO);
+
+    /**
+     * 获取销售合同信息分页列表
+     *
+     * @param pageReqVO 分页参数
+     * @return 销售合同信息分页列表
+     */
+    List<CustomerContractRespVO> getPageList(@Param("page") CustomerContractPageReqVO pageReqVO);
+
+    /**
+     * 物理删除销售合同信息
+     *
+     * @param id 编号
+     * @return 是否删除成功
+     */
+    Integer deleteCustomerContractOriginal(Long id);
+
+}

+ 34 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/dal/mysql/suppliercontract/SupplierContractHistoryMapper.java

@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.contract.dal.mysql.suppliercontract;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+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.contract.dal.dataobject.suppliercontract.SupplierContractHistoryDO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 采购合同历史信息 Mapper
+ *
+ * @author dp
+ */
+@Mapper
+public interface SupplierContractHistoryMapper extends BaseMapperX<SupplierContractHistoryDO> {
+
+    default PageResult<SupplierContractHistoryDO> selectPage(PageParam reqVO, String code) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<SupplierContractHistoryDO>()
+                .eq(SupplierContractHistoryDO::getSupplierContractCode, code)
+                .orderByDesc(SupplierContractHistoryDO::getId));
+    }
+
+    default int deleteByCode(String code) {
+        return delete(SupplierContractHistoryDO::getSupplierContractCode, code);
+    }
+
+    long getPageCount(@Param("page") PageParam pageReqVO, @Param("code") String code);
+
+    List<SupplierContractHistoryDO> getPageList(@Param("page") PageParam pageReqVO, @Param("code") String code);
+}

+ 60 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/dal/mysql/suppliercontract/SupplierContractMapper.java

@@ -0,0 +1,60 @@
+package cn.iocoder.yudao.module.contract.dal.mysql.suppliercontract;
+
+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.contract.controller.admin.suppliercontract.vo.SupplierContractPageReqVO;
+import cn.iocoder.yudao.module.contract.controller.admin.suppliercontract.vo.SupplierContractRespVO;
+import cn.iocoder.yudao.module.contract.dal.dataobject.suppliercontract.SupplierContractDO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 采购合同信息 Mapper
+ *
+ * @author dp
+ */
+@Mapper
+public interface SupplierContractMapper extends BaseMapperX<SupplierContractDO> {
+
+    default PageResult<SupplierContractDO> selectPage(SupplierContractPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<SupplierContractDO>()
+                .eqIfPresent(SupplierContractDO::getSupplierContractCode, reqVO.getSupplierContractCode())
+                .likeIfPresent(SupplierContractDO::getSupplierContractName, reqVO.getSupplierContractName())
+                .eqIfPresent(SupplierContractDO::getIsFrameContract, reqVO.getIsFrameContract())
+                .likeIfPresent(SupplierContractDO::getSupplierName, reqVO.getSupplierName())
+                .betweenIfPresent(SupplierContractDO::getStartDate, reqVO.getStartDate())
+                .betweenIfPresent(SupplierContractDO::getEndDate, reqVO.getEndDate())
+                .eqIfPresent(SupplierContractDO::getDeptId, reqVO.getDeptId())
+                .eqIfPresent(SupplierContractDO::getContractStatus, reqVO.getContractStatus())
+                .eqIfPresent(SupplierContractDO::getClosed, reqVO.getClosed())
+                .eqIfPresent(SupplierContractDO::getTerminate, reqVO.getTerminate())
+                .orderByDesc(SupplierContractDO::getId));
+    }
+
+    /**
+     * 获取采购合同信息总数量
+     *
+     * @param pageReqVO 分页参数
+     * @return 采购合同信息分页总数量
+     */
+    long getPageCount(@Param("page") SupplierContractPageReqVO pageReqVO);
+
+    /**
+     * 获取采购合同信息分页列表
+     *
+     * @param pageReqVO 分页参数
+     * @return 采购合同信息分页列表
+     */
+    List<SupplierContractRespVO> getPageList(@Param("page") SupplierContractPageReqVO pageReqVO);
+
+    /**
+     * 物理删除采购合同信息
+     *
+     * @param id 编号
+     * @return 是否删除成功
+     */
+    Integer deleteSupplierContractOriginal(Long id);
+}

+ 29 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/framework/config/ContractWebConfiguration.java

@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.module.contract.framework.config;
+
+
+import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration;
+import org.springdoc.core.GroupedOpenApi;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 采购、销售模块的Web配置类
+ * 用于配置模块相关的Web功能,例如Swagger文档分组
+ */
+@Configuration(proxyBeanMethods = false)
+public class ContractWebConfiguration {
+
+    /**
+     * 配置Swagger文档的分组
+     * 这样可以将采购、销售模块的API接口文档独立分组,便于在Swagger UI中管理和查看
+     *
+     * @return 分组配置对象
+     */
+    @Bean
+    public GroupedOpenApi contractGroupedOpenApi() {
+        return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("contract");
+    }
+
+}
+
+

+ 160 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/service/customercontract/CustomerContractService.java

@@ -0,0 +1,160 @@
+package cn.iocoder.yudao.module.contract.service.customercontract;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.contract.controller.admin.customercontract.vo.*;
+import cn.iocoder.yudao.module.contract.dal.dataobject.customercontract.CustomerContractDO;
+import cn.iocoder.yudao.module.contract.dal.dataobject.customercontract.CustomerContractHistoryDO;
+
+import javax.validation.Valid;
+
+/**
+ * 销售合同信息 Service 接口
+ *
+ * @author dp
+ */
+public interface CustomerContractService {
+
+    /**
+     * 获取供应商合同编号
+     * 供应商合同编号是标识供应商合同的唯一代码
+     *
+     * @return 供应商合同编号
+     */
+    String getCustomerContractCode();
+
+    /**
+     * 创建销售合同信息
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createCustomerContract(@Valid CustomerContractSaveReqVO createReqVO);
+
+    /**
+     * 更新销售合同信息
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateCustomerContract(@Valid CustomerContractSaveReqVO updateReqVO);
+
+    /**
+     * 删除销售合同信息
+     *
+     * @param id 编号
+     */
+    void deleteCustomerContract(Long id);
+
+    /**
+     * 获得销售合同信息
+     *
+     * @param id 编号
+     * @return 销售合同信息
+     */
+    CustomerContractDO getCustomerContract(Long id);
+
+    /**
+     * 获得销售合同信息分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 销售合同信息分页
+     */
+    PageResult<CustomerContractRespVO> getCustomerContractPage(CustomerContractPageReqVO pageReqVO);
+
+    /**
+     * 开启销售合同
+     *
+     * @param id 销售合同id
+     * @return 影响行数
+     */
+    Integer openCustomerContract(Long id);
+
+
+    /**
+     * 关闭销售合同
+     *
+     * @param closeReqVO 关闭请求对象,包含关闭所需的必要信息
+     *                   如合同ID、关闭原因等
+     * @return 返回操作结果,通常是一个标识操作成功与否的整数
+     * 比如:1表示成功,0表示失败
+     */
+    Integer closeCustomerContract(CustomerContractCloseReqVO closeReqVO);
+
+    /**
+     * 终止销售合同
+     *
+     * @param terminatedReqVO 终止请求对象,包含了终止合同所需的各种信息,如合同ID、终止原因等
+     * @return 返回处理结果,通常是处理状态(如成功或失败)的标识,或者处理后的结果数据
+     */
+    Integer terminateCustomerContract(CustomerContractTerminatedReqVO terminatedReqVO);
+
+    /**
+     * 修改合同状态
+     *
+     * @param statusReqVO 供应商合同状态请求对象,包含要更新的状态信息
+     * @return 更新操作的状态码,表示成功与否
+     */
+    Integer editCustomerStatus(CustomerContractStatusReqVO statusReqVO);
+
+
+    CustomerContractDO getCustomerContractByCode(String customerContractCode);
+
+    // ==================== 子表(销售合同历史信息) ====================
+
+    /**
+     * 获得销售合同历史信息分页
+     *
+     * @param pageReqVO 分页查询
+     * @param code 合同编号,年月日+uuid
+     * @return 销售合同历史信息分页
+     */
+    PageResult<CustomerContractHistoryDO> getCustomerContractHistoryPage(PageParam pageReqVO, String code);
+
+    /**
+     * 创建销售合同历史信息
+     *
+     * @param customerContractHistory 创建信息
+     * @return 编号
+     */
+    Long createCustomerContractHistory(@Valid CustomerContractHistoryDO customerContractHistory);
+
+    // /**
+    //  * 更新销售合同历史信息
+    //  *
+    //  * @param customerContractHistory 更新信息
+    //  */
+    // void updateCustomerContractHistory(@Valid CustomerContractHistoryDO customerContractHistory);
+    //
+    // /**
+    //  * 删除销售合同历史信息
+    //  *
+    //  * @param id 编号
+    //  */
+    // void deleteCustomerContractHistory(Long id);
+
+    /**
+     * 物理删除销售合同信息
+     *
+     * @param id 编号
+     * @return 影响行数
+     */
+    Integer deleteCustomerContractOriginal(Long id);
+
+
+    /**
+     * 变更销售合同信息
+     *
+     * @param updateReqVO 更新信息
+     */
+    void alterCustomerContract(CustomerContractSaveReqVO updateReqVO);
+
+
+    /**
+     * 获得销售合同历史信息
+     *
+     * @param id 编号
+     * @return 销售合同历史信息
+     */
+    CustomerContractHistoryDO getCustomerContractHistory(Long id);
+
+}

+ 322 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/service/customercontract/CustomerContractServiceImpl.java

@@ -0,0 +1,322 @@
+package cn.iocoder.yudao.module.contract.service.customercontract;
+
+import cn.hutool.core.util.IdUtil;
+import cn.iocoder.yudao.framework.common.enums.GeneralStatusEnum;
+import cn.iocoder.yudao.framework.common.exception.ErrorCode;
+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.security.core.util.SecurityFrameworkUtils;
+import cn.iocoder.yudao.module.contract.controller.admin.customercontract.vo.*;
+import cn.iocoder.yudao.module.contract.dal.dataobject.customercontract.CustomerContractDO;
+import cn.iocoder.yudao.module.contract.dal.dataobject.customercontract.CustomerContractHistoryDO;
+import cn.iocoder.yudao.module.contract.dal.mysql.customercontract.CustomerContractHistoryMapper;
+import cn.iocoder.yudao.module.contract.dal.mysql.customercontract.CustomerContractMapper;
+import cn.iocoder.yudao.module.contract.enums.ContractStatusEnum;
+import cn.iocoder.yudao.module.employee.api.EmployeeApi;
+import cn.iocoder.yudao.module.employee.api.dto.EmployeeRespDTO;
+import cn.iocoder.yudao.module.infra.api.file.FileApi;
+import cn.iocoder.yudao.module.system.api.dept.DeptApi;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.Objects;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.contract.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.module.employee.enums.ErrorCodeConstants.EMPLOYEE_INFO_NOT_EXISTS;
+
+/**
+ * 销售合同信息 Service 实现类
+ *
+ * @author dp
+ */
+@Service
+@Validated
+public class CustomerContractServiceImpl implements CustomerContractService {
+
+    @Resource
+    private CustomerContractMapper customerContractMapper;
+    @Resource
+    private CustomerContractHistoryMapper customerContractHistoryMapper;
+
+    @Resource
+    private FileApi fileApi;
+
+    @Resource
+    private EmployeeApi employeeApi;
+
+    @Resource
+    private DeptApi deptApi;
+
+    @Override
+    public String getCustomerContractCode() {
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
+        String format = formatter.format(LocalDateTime.now());
+        return format + IdUtil.fastSimpleUUID();
+    }
+
+    @Override
+    public Long createCustomerContract(CustomerContractSaveReqVO createReqVO) {
+        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
+        EmployeeRespDTO loginEmployee = employeeApi.getEmployeeByUserId(loginUserId);
+        if (Objects.isNull(loginEmployee)) {
+            throw exception(new ErrorCode(EMPLOYEE_INFO_NOT_EXISTS.getCode(), "登录用户员工信息不存在"));
+        }
+        // 插入
+        CustomerContractDO customerContract = BeanUtils.toBean(createReqVO, CustomerContractDO.class);
+        // uuid
+        customerContract.setCustomerContractUuid(IdUtil.fastSimpleUUID());
+        // 负责人及部门
+        Long ownerEmployeeId = createReqVO.getOwnerEmployeeId();
+        EmployeeRespDTO ownerEmployee = employeeApi.getEmployeeById(ownerEmployeeId);
+        if (Objects.isNull(ownerEmployee)) {
+            throw exception(EMPLOYEE_INFO_NOT_EXISTS);
+        }
+        Long deptId = ownerEmployee.getDeptId();
+        if (Objects.nonNull(deptId)) {
+            customerContract.setDeptId(deptId);
+        }
+        // 合同状态:0未归档
+        customerContract.setContractStatus(ContractStatusEnum.UNARCHIVED.getStatus());
+        // 是否关闭:0否
+        customerContract.setClosed(GeneralStatusEnum.NO.getStatus());
+        // 是否终止:0否
+        customerContract.setTerminate(GeneralStatusEnum.NO.getStatus());
+        // 是否变更
+        if (Objects.isNull(createReqVO.getIsChange())) {
+            customerContract.setIsChange(GeneralStatusEnum.NO.getStatus());
+        }
+
+        // 创建人
+        customerContract.setCreator(String.valueOf(loginEmployee.getId()));
+
+        customerContractMapper.insert(customerContract);
+
+        // 附件
+        fileApi.updateFileBiz(createReqVO.getFileIdList(), customerContract.getCustomerContractUuid());
+
+        // 返回
+        return customerContract.getId();
+    }
+
+    @Override
+    public void updateCustomerContract(CustomerContractSaveReqVO updateReqVO) {
+        // 校验存在
+        CustomerContractDO customerContractDO = validateCustomerContractExists(updateReqVO.getId());
+        // 更新
+        CustomerContractDO updateObj = BeanUtils.toBean(updateReqVO, CustomerContractDO.class);
+        // 负责人及部门
+        Long ownerEmployeeId = updateReqVO.getOwnerEmployeeId();
+        EmployeeRespDTO ownerEmployee = employeeApi.getEmployeeById(ownerEmployeeId);
+        if (Objects.isNull(ownerEmployee)) {
+            throw exception(EMPLOYEE_INFO_NOT_EXISTS);
+        }
+        Long deptId = ownerEmployee.getDeptId();
+        if (Objects.nonNull(deptId)) {
+            updateObj.setDeptId(deptId);
+        }
+        customerContractMapper.updateById(updateObj);
+
+        // 附件
+        fileApi.updateFileBiz(updateReqVO.getFileIdList(), customerContractDO.getCustomerContractUuid());
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deleteCustomerContract(Long id) {
+        // 校验存在
+        CustomerContractDO customerContractDO = validateCustomerContractExists(id);
+        // 删除
+        customerContractMapper.deleteById(id);
+
+        // 删除子表
+        // deleteCustomerContractHistoryByCode(customerContractDO.getCustomerContractCode());
+    }
+
+    @Override
+    public Integer deleteCustomerContractOriginal(Long id) {
+        // 校验存在
+        CustomerContractDO customerContractDO = validateCustomerContractExists(id);
+        return customerContractMapper.deleteCustomerContractOriginal(id);
+    }
+
+    private CustomerContractDO validateCustomerContractExists(Long id) {
+        CustomerContractDO customerContractDO = customerContractMapper.selectById(id);
+        if (customerContractDO == null) {
+            throw exception(CUSTOMER_CONTRACT_NOT_EXISTS);
+        }
+        return customerContractDO;
+    }
+
+    @Override
+    public CustomerContractDO getCustomerContract(Long id) {
+        return customerContractMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<CustomerContractRespVO> getCustomerContractPage(CustomerContractPageReqVO pageReqVO) {
+        pageReqVO.setPageNo((pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize());
+
+        long pageCount = -1;
+        if (!PageParam.PAGE_SIZE_NONE.equals(pageReqVO.getPageSize())) {
+            pageCount = customerContractMapper.getPageCount(pageReqVO);
+        }
+
+        if (pageCount == 0) {
+            return PageResult.empty();
+        }
+
+        List<CustomerContractRespVO> pageList = customerContractMapper.getPageList(pageReqVO);
+
+        return new PageResult<>(pageList, pageCount);
+    }
+
+    @Override
+    public Integer openCustomerContract(Long id) {
+        CustomerContractDO customerContractDO = validateCustomerContractExists(id);
+        if (GeneralStatusEnum.NO.getStatus().equals(customerContractDO.getClosed())) {
+            throw exception(CUSTOMER_CONTRACT_NOT_CLOSED);
+        }
+        CustomerContractDO build = CustomerContractDO.builder()
+                .id(id)
+                .closed(GeneralStatusEnum.NO.getStatus())
+                .build();
+        return customerContractMapper.updateById(build);
+    }
+
+    @Override
+    public Integer closeCustomerContract(CustomerContractCloseReqVO closeReqVO) {
+        CustomerContractDO customerContractDO = validateCustomerContractExists(closeReqVO.getId());
+
+        if (GeneralStatusEnum.YES.getStatus().equals(customerContractDO.getClosed())) {
+            throw exception(new ErrorCode(CUSTOMER_CONTRACT_NOT_CLOSED.getCode(), "合同已经是关闭状态"));
+        }
+
+        CustomerContractDO build = CustomerContractDO.builder()
+                .id(closeReqVO.getId())
+                .closed(GeneralStatusEnum.YES.getStatus())
+                .closeReason(closeReqVO.getCloseReason())
+                .build();
+
+        return customerContractMapper.updateById(build);
+    }
+
+    @Override
+    public Integer terminateCustomerContract(CustomerContractTerminatedReqVO terminatedReqVO) {
+        CustomerContractDO customerContractDO = validateCustomerContractExists(terminatedReqVO.getId());
+        if (GeneralStatusEnum.YES.getStatus().equals(customerContractDO.getTerminate())) {
+            throw exception(new ErrorCode(CUSTOMER_CONTRACT_NOT_CLOSED.getCode(), "合同已经是终止状态"));
+        }
+        CustomerContractDO build = CustomerContractDO.builder()
+                .id(terminatedReqVO.getId())
+                .terminate(GeneralStatusEnum.YES.getStatus())
+                .terminateDate(terminatedReqVO.getTerminateDate())
+                .terminateReason(terminatedReqVO.getTerminateReason())
+                .build();
+        return customerContractMapper.updateById(build);
+    }
+
+    @Override
+    public Integer editCustomerStatus(CustomerContractStatusReqVO statusReqVO) {
+        CustomerContractDO customerContractDO = validateCustomerContractExists(statusReqVO.getId());
+
+        CustomerContractDO build = CustomerContractDO.builder()
+                .id(statusReqVO.getId())
+                .contractStatus(statusReqVO.getContractStatus())
+                .build();
+        return customerContractMapper.updateById(build);
+    }
+
+    @Override
+    public CustomerContractDO getCustomerContractByCode(String customerContractCode) {
+        return customerContractMapper.selectOne(CustomerContractDO::getCustomerContractCode, customerContractCode);
+    }
+
+    // ==================== 子表(销售合同历史信息) ====================
+
+    @Override
+    public PageResult<CustomerContractHistoryDO> getCustomerContractHistoryPage(PageParam pageReqVO, String code) {
+        pageReqVO.setPageNo((pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize());
+
+        long pageCount = -1;
+        if (!PageParam.PAGE_SIZE_NONE.equals(pageReqVO.getPageSize())) {
+            pageCount = customerContractHistoryMapper.getPageCount(pageReqVO, code);
+        }
+
+        if (pageCount == 0) {
+            return PageResult.empty();
+        }
+
+        List<CustomerContractHistoryDO> pageList = customerContractHistoryMapper.getPageList(pageReqVO, code);
+
+        return new PageResult<>(pageList, pageCount);
+    }
+
+    @Override
+    public Long createCustomerContractHistory(CustomerContractHistoryDO customerContractHistory) {
+        customerContractHistoryMapper.insert(customerContractHistory);
+        return customerContractHistory.getId();
+    }
+
+    // @Override
+    // public void updateCustomerContractHistory(CustomerContractHistoryDO customerContractHistory) {
+    //     // 校验存在
+    //     validateCustomerContractHistoryExists(customerContractHistory.getId());
+    //     // 更新
+    //     customerContractHistoryMapper.updateById(customerContractHistory);
+    // }
+    //
+    // @Override
+    // public void deleteCustomerContractHistory(Long id) {
+    //     // 校验存在
+    //     validateCustomerContractHistoryExists(id);
+    //     // 删除
+    //     customerContractHistoryMapper.deleteById(id);
+    // }
+
+    @Override
+    public CustomerContractHistoryDO getCustomerContractHistory(Long id) {
+        // validateCustomerContractHistoryExists(id);
+        return customerContractHistoryMapper.selectById(id);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void alterCustomerContract(CustomerContractSaveReqVO updateReqVO) {
+        String customerContractCode = updateReqVO.getCustomerContractCode();
+        CustomerContractDO customerContract = this.getCustomerContractByCode(customerContractCode);
+        if (Objects.isNull(customerContract)) {
+            throw exception(CUSTOMER_CONTRACT_NOT_EXISTS);
+        }
+        // 物理删除原合同信息
+        this.deleteCustomerContractOriginal(customerContract.getId());
+        // 添加到历史合同信息表中
+        CustomerContractHistoryDO customerContractHistoryDO = BeanUtils.toBean(customerContract, CustomerContractHistoryDO.class);
+        customerContractHistoryDO.setId(null);
+        this.createCustomerContractHistory(customerContractHistoryDO);
+        // 新增新合同
+        updateReqVO.setId(null);
+        updateReqVO.setIsChange(GeneralStatusEnum.YES.getStatus());
+        this.createCustomerContract(updateReqVO);
+    }
+
+    private CustomerContractHistoryDO validateCustomerContractHistoryExists(Long id) {
+        CustomerContractHistoryDO customerContractHistoryDO = customerContractHistoryMapper.selectById(id);
+        if (customerContractHistoryDO == null) {
+            throw exception(CUSTOMER_CONTRACT_HISTORY_NOT_EXISTS);
+        }
+        return customerContractHistoryDO;
+    }
+
+    private void deleteCustomerContractHistoryByCode(String code) {
+        customerContractHistoryMapper.deleteByCode(code);
+    }
+
+
+}

+ 160 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/service/suppliercontract/SupplierContractService.java

@@ -0,0 +1,160 @@
+package cn.iocoder.yudao.module.contract.service.suppliercontract;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.contract.controller.admin.suppliercontract.vo.*;
+import cn.iocoder.yudao.module.contract.dal.dataobject.suppliercontract.SupplierContractDO;
+import cn.iocoder.yudao.module.contract.dal.dataobject.suppliercontract.SupplierContractHistoryDO;
+
+import javax.validation.Valid;
+
+/**
+ * 采购合同信息 Service 接口
+ *
+ * @author dp
+ */
+public interface SupplierContractService {
+
+    /**
+     * 获取供应商合同编号
+     * 供应商合同编号是标识供应商合同的唯一代码
+     *
+     * @return 供应商合同编号
+     */
+    String getSupplierContractCode();
+
+    /**
+     * 创建采购合同信息
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createSupplierContract(@Valid SupplierContractSaveReqVO createReqVO);
+
+    /**
+     * 更新采购合同信息
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateSupplierContract(@Valid SupplierContractSaveReqVO updateReqVO);
+
+    /**
+     * 删除采购合同信息
+     *
+     * @param id 编号
+     */
+    void deleteSupplierContract(Long id);
+
+    /**
+     * 获得采购合同信息
+     *
+     * @param id 编号
+     * @return 采购合同信息
+     */
+    SupplierContractDO getSupplierContract(Long id);
+
+    /**
+     * 获得采购合同信息分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 采购合同信息分页
+     */
+    PageResult<SupplierContractRespVO> getSupplierContractPage(SupplierContractPageReqVO pageReqVO);
+
+    /**
+     * 开启采购合同
+     *
+     * @param id 采购合同id
+     * @return 影响行数
+     */
+    Integer openSupplierContract(Long id);
+
+
+    /**
+     * 关闭采购合同
+     *
+     * @param closeReqVO 关闭请求对象,包含关闭所需的必要信息
+     *                   如合同ID、关闭原因等
+     * @return 返回操作结果,通常是一个标识操作成功与否的整数
+     * 比如:1表示成功,0表示失败
+     */
+    Integer closeSupplierContract(SupplierContractCloseReqVO closeReqVO);
+
+    /**
+     * 终止采购合同
+     *
+     * @param terminatedReqVO 终止请求对象,包含了终止合同所需的各种信息,如合同ID、终止原因等
+     * @return 返回处理结果,通常是处理状态(如成功或失败)的标识,或者处理后的结果数据
+     */
+    Integer terminateSupplierContract(SupplierContractTerminatedReqVO terminatedReqVO);
+
+    /**
+     * 修改合同状态
+     *
+     * @param statusReqVO 供应商合同状态请求对象,包含要更新的状态信息
+     * @return 更新操作的状态码,表示成功与否
+     */
+    Integer editSupplierStatus(SupplierContractStatusReqVO statusReqVO);
+
+
+    SupplierContractDO getSupplierContractByCode(String supplierContractCode);
+
+    // ==================== 子表(采购合同历史信息) ====================
+
+    /**
+     * 获得采购合同历史信息分页
+     *
+     * @param pageReqVO 分页查询
+     * @param code 合同编号,年月日+uuid
+     * @return 采购合同历史信息分页
+     */
+    PageResult<SupplierContractHistoryDO> getSupplierContractHistoryPage(PageParam pageReqVO, String code);
+
+    /**
+     * 创建采购合同历史信息
+     *
+     * @param supplierContractHistory 创建信息
+     * @return 编号
+     */
+    Long createSupplierContractHistory(@Valid SupplierContractHistoryDO supplierContractHistory);
+
+    // /**
+    //  * 更新采购合同历史信息
+    //  *
+    //  * @param supplierContractHistory 更新信息
+    //  */
+    // void updateSupplierContractHistory(@Valid SupplierContractHistoryDO supplierContractHistory);
+    //
+    // /**
+    //  * 删除采购合同历史信息
+    //  *
+    //  * @param id 编号
+    //  */
+    // void deleteSupplierContractHistory(Long id);
+
+    /**
+     * 物理删除采购合同信息
+     *
+     * @param id 编号
+     * @return 影响行数
+     */
+    Integer deleteSupplierContractOriginal(Long id);
+
+
+    /**
+     * 变更采购合同信息
+     *
+     * @param updateReqVO 更新信息
+     */
+    void alterSupplierContract(SupplierContractSaveReqVO updateReqVO);
+
+
+	/**
+	 * 获得采购合同历史信息
+	 *
+	 * @param id 编号
+     * @return 采购合同历史信息
+	 */
+    SupplierContractHistoryDO getSupplierContractHistory(Long id);
+
+}

+ 318 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/java/cn/iocoder/yudao/module/contract/service/suppliercontract/SupplierContractServiceImpl.java

@@ -0,0 +1,318 @@
+package cn.iocoder.yudao.module.contract.service.suppliercontract;
+
+import cn.hutool.core.util.IdUtil;
+import cn.iocoder.yudao.framework.common.enums.GeneralStatusEnum;
+import cn.iocoder.yudao.framework.common.exception.ErrorCode;
+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.security.core.util.SecurityFrameworkUtils;
+import cn.iocoder.yudao.module.contract.controller.admin.suppliercontract.vo.*;
+import cn.iocoder.yudao.module.contract.dal.dataobject.suppliercontract.SupplierContractDO;
+import cn.iocoder.yudao.module.contract.dal.dataobject.suppliercontract.SupplierContractHistoryDO;
+import cn.iocoder.yudao.module.contract.dal.mysql.suppliercontract.SupplierContractHistoryMapper;
+import cn.iocoder.yudao.module.contract.dal.mysql.suppliercontract.SupplierContractMapper;
+import cn.iocoder.yudao.module.contract.enums.ContractStatusEnum;
+import cn.iocoder.yudao.module.employee.api.EmployeeApi;
+import cn.iocoder.yudao.module.employee.api.dto.EmployeeRespDTO;
+import cn.iocoder.yudao.module.infra.api.file.FileApi;
+import cn.iocoder.yudao.module.system.api.dept.DeptApi;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.Objects;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.contract.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.module.employee.enums.ErrorCodeConstants.EMPLOYEE_INFO_NOT_EXISTS;
+
+/**
+ * 采购合同信息 Service 实现类
+ *
+ * @author dp
+ */
+@Service
+@Validated
+public class SupplierContractServiceImpl implements SupplierContractService {
+
+    @Resource
+    private SupplierContractMapper supplierContractMapper;
+    @Resource
+    private SupplierContractHistoryMapper supplierContractHistoryMapper;
+
+    @Resource
+    private FileApi fileApi;
+
+    @Resource
+    private EmployeeApi employeeApi;
+
+    @Resource
+    private DeptApi deptApi;
+
+    @Override
+    public String getSupplierContractCode() {
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
+        String format = formatter.format(LocalDateTime.now());
+        return format + IdUtil.fastSimpleUUID();
+    }
+
+    @Override
+    public Long createSupplierContract(SupplierContractSaveReqVO createReqVO) {
+        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
+        EmployeeRespDTO loginEmployee = employeeApi.getEmployeeByUserId(loginUserId);
+        if (Objects.isNull(loginEmployee)) {
+            throw exception(new ErrorCode(EMPLOYEE_INFO_NOT_EXISTS.getCode(), "登录用户员工信息不存在"));
+        }
+        // 插入
+        SupplierContractDO supplierContract = BeanUtils.toBean(createReqVO, SupplierContractDO.class);
+        // uuid
+        supplierContract.setSupplierContractUuid(IdUtil.fastSimpleUUID());
+        // 负责人及部门
+        Long ownerEmployeeId = createReqVO.getOwnerEmployeeId();
+        EmployeeRespDTO ownerEmployee = employeeApi.getEmployeeById(ownerEmployeeId);
+        if (Objects.isNull(ownerEmployee)) {
+            throw exception(EMPLOYEE_INFO_NOT_EXISTS);
+        }
+        Long deptId = ownerEmployee.getDeptId();
+        if (Objects.nonNull(deptId)) {
+            supplierContract.setDeptId(deptId);
+        }
+        // 合同状态:0未归档
+        supplierContract.setContractStatus(ContractStatusEnum.UNARCHIVED.getStatus());
+        // 是否关闭:0否
+        supplierContract.setClosed(GeneralStatusEnum.NO.getStatus());
+        // 是否终止:0否
+        supplierContract.setTerminate(GeneralStatusEnum.NO.getStatus());
+        // 是否变更
+        if (Objects.isNull(createReqVO.getIsChange())) {
+            supplierContract.setIsChange(GeneralStatusEnum.NO.getStatus());
+        }
+
+        // 创建人
+        supplierContract.setCreator(String.valueOf(loginEmployee.getId()));
+
+        supplierContractMapper.insert(supplierContract);
+
+        // 附件
+        fileApi.updateFileBiz(createReqVO.getFileIdList(), supplierContract.getSupplierContractUuid());
+
+        // 返回
+        return supplierContract.getId();
+    }
+
+    @Override
+    public void updateSupplierContract(SupplierContractSaveReqVO updateReqVO) {
+        // 校验存在
+        SupplierContractDO supplierContractDO = validateSupplierContractExists(updateReqVO.getId());
+        // 更新
+        SupplierContractDO updateObj = BeanUtils.toBean(updateReqVO, SupplierContractDO.class);
+        // 负责人及部门
+        Long ownerEmployeeId = updateReqVO.getOwnerEmployeeId();
+        EmployeeRespDTO ownerEmployee = employeeApi.getEmployeeById(ownerEmployeeId);
+        if (Objects.isNull(ownerEmployee)) {
+            throw exception(EMPLOYEE_INFO_NOT_EXISTS);
+        }
+        Long deptId = ownerEmployee.getDeptId();
+        if (Objects.nonNull(deptId)) {
+            updateObj.setDeptId(deptId);
+        }
+        supplierContractMapper.updateById(updateObj);
+
+        // 附件
+        fileApi.updateFileBiz(updateReqVO.getFileIdList(), supplierContractDO.getSupplierContractUuid());
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deleteSupplierContract(Long id) {
+        // 校验存在
+        SupplierContractDO supplierContractDO = validateSupplierContractExists(id);
+        // 删除
+        supplierContractMapper.deleteById(id);
+
+        // 删除子表
+        // deleteSupplierContractHistoryByCode(supplierContractDO.getSupplierContractCode());
+    }
+
+    @Override
+    public Integer deleteSupplierContractOriginal(Long id) {
+        // 校验存在
+        SupplierContractDO supplierContractDO = validateSupplierContractExists(id);
+        return supplierContractMapper.deleteSupplierContractOriginal(id);
+    }
+
+    private SupplierContractDO validateSupplierContractExists(Long id) {
+        SupplierContractDO supplierContractDO = supplierContractMapper.selectById(id);
+        if (supplierContractDO == null) {
+            throw exception(SUPPLIER_CONTRACT_NOT_EXISTS);
+        }
+        return supplierContractDO;
+    }
+
+    @Override
+    public SupplierContractDO getSupplierContract(Long id) {
+        return supplierContractMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<SupplierContractRespVO> getSupplierContractPage(SupplierContractPageReqVO pageReqVO) {
+        pageReqVO.setPageNo((pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize());
+
+        long pageCount = -1;
+        if (!PageParam.PAGE_SIZE_NONE.equals(pageReqVO.getPageSize())) {
+            pageCount = supplierContractMapper.getPageCount(pageReqVO);
+        }
+
+        if (pageCount == 0) {
+            return PageResult.empty();
+        }
+
+        List<SupplierContractRespVO> pageList = supplierContractMapper.getPageList(pageReqVO);
+
+        return new PageResult<>(pageList, pageCount);
+    }
+
+    @Override
+    public Integer openSupplierContract(Long id) {
+        SupplierContractDO supplierContractDO = validateSupplierContractExists(id);
+        if (GeneralStatusEnum.NO.getStatus().equals(supplierContractDO.getClosed())) {
+            throw exception(SUPPLIER_CONTRACT_NOT_CLOSED);
+        }
+        SupplierContractDO build = SupplierContractDO.builder()
+                .id(id)
+                .closed(GeneralStatusEnum.NO.getStatus())
+                .build();
+        return supplierContractMapper.updateById(build);
+    }
+
+    @Override
+    public Integer closeSupplierContract(SupplierContractCloseReqVO closeReqVO) {
+        SupplierContractDO supplierContractDO = validateSupplierContractExists(closeReqVO.getId());
+
+        if (GeneralStatusEnum.YES.getStatus().equals(supplierContractDO.getClosed())) {
+            throw exception(new ErrorCode(SUPPLIER_CONTRACT_NOT_CLOSED.getCode(), "合同已经是关闭状态"));
+        }
+
+        SupplierContractDO build = SupplierContractDO.builder()
+                .id(closeReqVO.getId())
+                .closed(GeneralStatusEnum.YES.getStatus())
+                .closeReason(closeReqVO.getCloseReason())
+                .build();
+
+        return supplierContractMapper.updateById(build);
+    }
+
+    @Override
+    public Integer terminateSupplierContract(SupplierContractTerminatedReqVO terminatedReqVO) {
+        SupplierContractDO supplierContractDO = validateSupplierContractExists(terminatedReqVO.getId());
+        if (GeneralStatusEnum.YES.getStatus().equals(supplierContractDO.getTerminate())) {
+            throw exception(new ErrorCode(SUPPLIER_CONTRACT_NOT_CLOSED.getCode(), "合同已经是终止状态"));
+        }
+        SupplierContractDO build = SupplierContractDO.builder()
+                .id(terminatedReqVO.getId())
+                .terminate(GeneralStatusEnum.YES.getStatus())
+                .terminateDate(terminatedReqVO.getTerminateDate())
+                .terminateReason(terminatedReqVO.getTerminateReason())
+                .build();
+        return supplierContractMapper.updateById(build);
+    }
+
+    @Override
+    public Integer editSupplierStatus(SupplierContractStatusReqVO statusReqVO) {
+        SupplierContractDO supplierContractDO = validateSupplierContractExists(statusReqVO.getId());
+
+        SupplierContractDO build = SupplierContractDO.builder()
+                .id(statusReqVO.getId())
+                .contractStatus(statusReqVO.getContractStatus())
+                .build();
+        return supplierContractMapper.updateById(build);
+    }
+
+    @Override
+    public SupplierContractDO getSupplierContractByCode(String supplierContractCode) {
+        return supplierContractMapper.selectOne(SupplierContractDO::getSupplierContractCode, supplierContractCode);
+    }
+
+    // ==================== 子表(采购合同历史信息) ====================
+
+    @Override
+    public PageResult<SupplierContractHistoryDO> getSupplierContractHistoryPage(PageParam pageReqVO, String code) {
+        pageReqVO.setPageNo((pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize());
+
+        long pageCount = -1;
+        if (!PageParam.PAGE_SIZE_NONE.equals(pageReqVO.getPageSize())) {
+            pageCount = supplierContractHistoryMapper.getPageCount(pageReqVO, code);
+        }
+
+        if (pageCount == 0) {
+            return PageResult.empty();
+        }
+
+        List<SupplierContractHistoryDO> pageList = supplierContractHistoryMapper.getPageList(pageReqVO, code);
+
+        return new PageResult<>(pageList, pageCount);
+    }
+
+    @Override
+    public Long createSupplierContractHistory(SupplierContractHistoryDO supplierContractHistory) {
+        supplierContractHistoryMapper.insert(supplierContractHistory);
+        return supplierContractHistory.getId();
+    }
+
+    // @Override
+    // public void updateSupplierContractHistory(SupplierContractHistoryDO supplierContractHistory) {
+    //     // 校验存在
+    //     validateSupplierContractHistoryExists(supplierContractHistory.getId());
+    //     // 更新
+    //     supplierContractHistoryMapper.updateById(supplierContractHistory);
+    // }
+    //
+    // @Override
+    // public void deleteSupplierContractHistory(Long id) {
+    //     // 校验存在
+    //     validateSupplierContractHistoryExists(id);
+    //     // 删除
+    //     supplierContractHistoryMapper.deleteById(id);
+    // }
+
+    @Override
+    public SupplierContractHistoryDO getSupplierContractHistory(Long id) {
+        return supplierContractHistoryMapper.selectById(id);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void alterSupplierContract(SupplierContractSaveReqVO updateReqVO) {
+        String supplierContractCode = updateReqVO.getSupplierContractCode();
+        SupplierContractDO supplierContract = this.getSupplierContractByCode(supplierContractCode);
+        if (Objects.isNull(supplierContract)) {
+            throw exception(SUPPLIER_CONTRACT_NOT_EXISTS);
+        }
+        // 物理删除原合同信息
+        this.deleteSupplierContractOriginal(supplierContract.getId());
+        // 添加到历史合同信息表中
+        SupplierContractHistoryDO supplierContractHistoryDO = BeanUtils.toBean(supplierContract, SupplierContractHistoryDO.class);
+        supplierContractHistoryDO.setId(null);
+        this.createSupplierContractHistory(supplierContractHistoryDO);
+        // 新增新合同
+        updateReqVO.setId(null);
+        updateReqVO.setIsChange(GeneralStatusEnum.YES.getStatus());
+        this.createSupplierContract(updateReqVO);
+    }
+
+    private void validateSupplierContractHistoryExists(Long id) {
+        if (supplierContractHistoryMapper.selectById(id) == null) {
+            throw exception(SUPPLIER_CONTRACT_HISTORY_NOT_EXISTS);
+        }
+    }
+
+    private void deleteSupplierContractHistoryByCode(String code) {
+        supplierContractHistoryMapper.deleteByCode(code);
+    }
+
+}

+ 91 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/resources/mapper/customercontract/CustomerContractHistoryMapper.xml

@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.iocoder.yudao.module.contract.dal.mysql.customercontract.CustomerContractHistoryMapper">
+
+    <!--
+        一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
+        无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
+        代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
+        文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
+     -->
+
+    <select id="getPageCount" resultType="java.lang.Long">
+        SELECT
+            count(fcch.id)
+        FROM
+            finance_customer_contract_history fcch
+            LEFT JOIN employee_info ei ON ei.id = fcch.owner_employee_id AND ei.deleted = 0
+            LEFT JOIN system_dept sd ON sd.id = fcch.dept_id AND sd.deleted = 0
+            LEFT JOIN employee_info ei2 ON ei2.id = fcch.creator AND ei2.deleted = 0
+        WHERE
+            fcch.deleted = 0
+        <if test="code != null and code != ''">
+            AND fcch.customer_contract_code = #{code}
+        </if>
+    </select>
+    <select id="getPageList"
+            resultType="cn.iocoder.yudao.module.contract.controller.admin.customercontract.vo.CustomerContractRespVO">
+        SELECT
+            fcch.id,
+            fcch.customer_contract_uuid,
+            fcch.customer_contract_code,
+            fcch.customer_contract_name,
+            fcch.is_frame_contract,
+               CASE
+                   WHEN fcch.is_frame_contract = 1 THEN '是'
+                   WHEN fcch.is_frame_contract = 0 THEN '否'
+                   ELSE '未知'
+               END AS isFrameContractDesc,
+            fcch.customer_id,
+            fcch.customer_name,
+            fcch.start_date,
+            fcch.end_date,
+            fcch.money,
+            fcch.owner_employee_id,
+               ei.name AS ownerEmployeeName,
+            fcch.dept_id,
+               sd.name AS deptName,
+            fcch.contract_status,
+                CASE
+                    WHEN fcch.contract_status = 0 THEN '未归档'
+                    WHEN fcch.contract_status = 1 THEN '已归档'
+                    WHEN fcch.contract_status = 2 THEN '已完结'
+                    ELSE '未知'
+                END AS contractStatusDesc,
+            fcch.closed,
+               CASE
+                    WHEN fcch.closed = 1 THEN '是'
+                    WHEN fcch.closed = 0 THEN '否'
+                    ELSE '未知'
+                END AS closedDesc,
+            fcch.close_reason,
+            fcch.terminate,
+               CASE
+                   WHEN fcch.terminate = 1 THEN '是'
+                   WHEN fcch.terminate = 0 THEN '否'
+                   ELSE '未知'
+               END AS terminateDesc,
+            fcch.terminate_date,
+            fcch.terminate_reason,
+            fcch.is_change,
+            fcch.remarks,
+            fcch.creator,
+               ei2.name AS creatorName,
+            fcch.create_time
+        FROM
+            finance_customer_contract_history fcch
+                LEFT JOIN employee_info ei ON ei.id = fcch.owner_employee_id AND ei.deleted = 0
+                LEFT JOIN system_dept sd ON sd.id = fcch.dept_id AND sd.deleted = 0
+                LEFT JOIN employee_info ei2 ON ei2.id = fcch.creator AND ei2.deleted = 0
+        WHERE
+            fcch.deleted = 0
+        <if test="code != null and code != ''">
+            AND fcch.customer_contract_code = #{code}
+        </if>
+        ORDER BY
+            fcch.create_time
+        <if test="page.pageSize != -1">
+            LIMIT #{page.pageNo}, #{page.pageSize}
+        </if>
+    </select>
+</mapper>

+ 161 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/resources/mapper/customercontract/CustomerContractMapper.xml

@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.iocoder.yudao.module.contract.dal.mysql.customercontract.CustomerContractMapper">
+
+    <!--
+        一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
+        无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
+        代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
+        文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
+     -->
+
+    <select id="getPageCount" resultType="java.lang.Long">
+        SELECT
+        count(fcc.id)
+        FROM
+        finance_customer_contract fcc
+        LEFT JOIN employee_info ei ON ei.id = fcc.owner_employee_id AND ei.deleted = 0
+        LEFT JOIN system_dept sd ON sd.id = fcc.dept_id AND sd.deleted = 0
+        LEFT JOIN employee_info ei2 ON ei2.id = fcc.creator AND ei2.deleted = 0
+        WHERE
+        fcc.deleted = 0
+        <if test="page.customerContractCode != null and page.customerContractCode != ''">
+            AND fcc.customer_contract_code like concat('%',#{page.customerContractCode},'%')
+        </if>
+        <if test="page.customerContractName != null and page.customerContractName != ''">
+            AND fcc.customer_contract_name like concat('%',#{page.customerContractName},'%')
+        </if>
+        <if test="page.isFrameContract != null">
+            AND fcc.is_frame_contract = #{page.isFrameContract}
+        </if>
+        <if test="page.customerId != null">
+            AND fcc.customer_id = #{page.customerId}
+        </if>
+        <if test="page.startDate != null and page.startDate.length > 0">
+            AND fcc.start_date BETWEEN #{page.startDate[0]} AND #{page.startDate[1]}
+        </if>
+        <if test="page.endDate != null and page.endDate.length > 0">
+            AND fcc.end_date BETWEEN #{page.endDate[0]} AND #{page.endDate[1]}
+        </if>
+        <if test="page.ownerEmployeeName != null and page.ownerEmployeeName != ''">
+            AND ei.name like concat('%',#{page.ownerEmployeeName},'%')
+        </if>
+        <if test="page.deptId != null">
+            AND fcc.dept_id = #{page.deptId}
+        </if>
+        <if test="page.contractStatus != null and page.contractStatus != ''">
+            AND fcc.contract_status = #{page.contractStatus}
+        </if>
+        <if test="page.closed != null">
+            AND fcc.closed = #{page.closed}
+        </if>
+        <if test="page.terminate != null">
+            AND fcc.terminate = #{page.terminate}
+        </if>
+    </select>
+    <select id="getPageList"
+            resultType="cn.iocoder.yudao.module.contract.controller.admin.customercontract.vo.CustomerContractRespVO">
+        SELECT
+        fcc.id,
+        fcc.customer_contract_uuid,
+        fcc.customer_contract_code,
+        fcc.customer_contract_name,
+        fcc.is_frame_contract,
+        CASE
+        WHEN fcc.is_frame_contract = 1 THEN '是'
+        WHEN fcc.is_frame_contract = 0 THEN '否'
+        ELSE '未知'
+        END AS isFrameContractDesc,
+        fcc.customer_id,
+        fcc.customer_name,
+        fcc.start_date,
+        fcc.end_date,
+        fcc.money,
+        fcc.owner_employee_id,
+        ei.name AS ownerEmployeeName,
+        fcc.dept_id,
+        sd.name AS deptName,
+        fcc.contract_status,
+        CASE
+        WHEN fcc.contract_status = 0 THEN '未归档'
+        WHEN fcc.contract_status = 1 THEN '已归档'
+        WHEN fcc.contract_status = 2 THEN '已完结'
+        ELSE '未知'
+        END AS contractStatusDesc,
+        fcc.closed,
+        CASE
+        WHEN fcc.closed = 1 THEN '是'
+        WHEN fcc.closed = 0 THEN '否'
+        ELSE '未知'
+        END AS closedDesc,
+        fcc.close_reason,
+        fcc.terminate,
+        CASE
+        WHEN fcc.terminate = 1 THEN '是'
+        WHEN fcc.terminate = 0 THEN '否'
+        ELSE '未知'
+        END AS terminateDesc,
+        fcc.terminate_date,
+        fcc.terminate_reason,
+        fcc.is_change,
+        fcc.remarks,
+        fcc.creator,
+        ei2.name AS creatorName,
+        fcc.create_time
+        FROM
+        finance_customer_contract fcc
+        LEFT JOIN employee_info ei ON ei.id = fcc.owner_employee_id AND ei.deleted = 0
+        LEFT JOIN system_dept sd ON sd.id = fcc.dept_id AND sd.deleted = 0
+        LEFT JOIN employee_info ei2 ON ei2.id = fcc.creator AND ei2.deleted = 0
+        WHERE
+        fcc.deleted = 0
+        <if test="page.customerContractCode != null and page.customerContractCode != ''">
+            AND fcc.customer_contract_code like concat('%',#{page.customerContractCode},'%')
+        </if>
+        <if test="page.customerContractName != null and page.customerContractName != ''">
+            AND fcc.customer_contract_name like concat('%',#{page.customerContractName},'%')
+        </if>
+        <if test="page.isFrameContract != null">
+            AND fcc.is_frame_contract = #{page.isFrameContract}
+        </if>
+        <if test="page.customerId != null">
+            AND fcc.customer_id = #{page.customerId}
+        </if>
+        <if test="page.startDate != null and page.startDate.length > 0">
+            AND fcc.start_date BETWEEN #{page.startDate[0]} AND #{page.startDate[1]}
+        </if>
+        <if test="page.endDate != null and page.endDate.length > 0">
+            AND fcc.end_date BETWEEN #{page.endDate[0]} AND #{page.endDate[1]}
+        </if>
+        <if test="page.ownerEmployeeName != null and page.ownerEmployeeName != ''">
+            AND ei.name like concat('%',#{page.ownerEmployeeName},'%')
+        </if>
+        <if test="page.deptId != null">
+            AND fcc.dept_id = #{page.deptId}
+        </if>
+        <if test="page.contractStatus != null and page.contractStatus != ''">
+            AND fcc.contract_status = #{page.contractStatus}
+        </if>
+        <if test="page.closed != null">
+            AND fcc.closed = #{page.closed}
+        </if>
+        <if test="page.terminate != null">
+            AND fcc.terminate = #{page.terminate}
+        </if>
+        ORDER BY
+        fcc.create_time DESC
+        <if test="page.pageSize != -1">
+            LIMIT #{page.pageNo}, #{page.pageSize}
+        </if>
+    </select>
+
+    <delete id="deleteCustomerContractOriginal">
+        DELETE
+        FROM
+            finance_customer_contract
+        WHERE
+            id = #{id}
+          AND deleted = 0
+    </delete>
+
+</mapper>

+ 91 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/resources/mapper/suppliercontract/SupplierContractHistoryMapper.xml

@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.iocoder.yudao.module.contract.dal.mysql.suppliercontract.SupplierContractHistoryMapper">
+
+    <!--
+        一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
+        无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
+        代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
+        文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
+     -->
+
+    <select id="getPageCount" resultType="java.lang.Long">
+        SELECT
+            count(fsch.id)
+        FROM
+            finance_supplier_contract_history fsch
+            LEFT JOIN employee_info ei ON ei.id = fsch.owner_employee_id AND ei.deleted = 0
+            LEFT JOIN system_dept sd ON sd.id = fsch.dept_id AND sd.deleted = 0
+            LEFT JOIN employee_info ei2 ON ei2.id = fsch.creator AND ei2.deleted = 0
+        WHERE
+            fsch.deleted = 0
+        <if test="code != null and code != ''">
+            AND fsch.supplier_contract_code = #{code}
+        </if>
+    </select>
+    <select id="getPageList"
+            resultType="cn.iocoder.yudao.module.contract.controller.admin.suppliercontract.vo.SupplierContractRespVO">
+        SELECT
+            fsch.id,
+            fsch.supplier_contract_uuid,
+            fsch.supplier_contract_code,
+            fsch.supplier_contract_name,
+            fsch.is_frame_contract,
+               CASE
+                   WHEN fsch.is_frame_contract = 1 THEN '是'
+                   WHEN fsch.is_frame_contract = 0 THEN '否'
+                   ELSE '未知'
+               END AS isFrameContractDesc,
+            fsch.supplier_id,
+            fsch.supplier_name,
+            fsch.start_date,
+            fsch.end_date,
+            fsch.money,
+            fsch.owner_employee_id,
+               ei.name AS ownerEmployeeName,
+            fsch.dept_id,
+               sd.name AS deptName,
+            fsch.contract_status,
+                CASE
+                    WHEN fsch.contract_status = 0 THEN '未归档'
+                    WHEN fsch.contract_status = 1 THEN '已归档'
+                    WHEN fsch.contract_status = 2 THEN '已完结'
+                    ELSE '未知'
+                END AS contractStatusDesc,
+            fsch.closed,
+               CASE
+                    WHEN fsch.closed = 1 THEN '是'
+                    WHEN fsch.closed = 0 THEN '否'
+                    ELSE '未知'
+                END AS closedDesc,
+            fsch.close_reason,
+            fsch.terminate,
+               CASE
+                   WHEN fsch.terminate = 1 THEN '是'
+                   WHEN fsch.terminate = 0 THEN '否'
+                   ELSE '未知'
+               END AS terminateDesc,
+            fsch.terminate_date,
+            fsch.terminate_reason,
+            fsch.is_change,
+            fsch.remarks,
+            fsch.creator,
+               ei2.name AS creatorName,
+            fsch.create_time
+        FROM
+            finance_supplier_contract_history fsch
+                LEFT JOIN employee_info ei ON ei.id = fsch.owner_employee_id AND ei.deleted = 0
+                LEFT JOIN system_dept sd ON sd.id = fsch.dept_id AND sd.deleted = 0
+                LEFT JOIN employee_info ei2 ON ei2.id = fsch.creator AND ei2.deleted = 0
+        WHERE
+            fsch.deleted = 0
+        <if test="code != null and code != ''">
+            AND fsch.supplier_contract_code = #{code}
+        </if>
+        ORDER BY
+            fsch.create_time
+        <if test="page.pageSize != -1">
+            LIMIT #{page.pageNo}, #{page.pageSize}
+        </if>
+    </select>
+</mapper>

+ 160 - 0
yudao-module-finance/yudao-module-contract-biz/src/main/resources/mapper/suppliercontract/SupplierContractMapper.xml

@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.iocoder.yudao.module.contract.dal.mysql.suppliercontract.SupplierContractMapper">
+
+    <!--
+        一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
+        无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
+        代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
+        文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
+     -->
+
+    <select id="getPageCount" resultType="java.lang.Long">
+        SELECT
+            count(fsc.id)
+        FROM
+            finance_supplier_contract fsc
+            LEFT JOIN employee_info ei ON ei.id = fsc.owner_employee_id AND ei.deleted = 0
+            LEFT JOIN system_dept sd ON sd.id = fsc.dept_id AND sd.deleted = 0
+            LEFT JOIN employee_info ei2 ON ei2.id = fsc.creator AND ei2.deleted = 0
+        WHERE
+            fsc.deleted = 0
+        <if test="page.supplierContractCode != null and page.supplierContractCode != ''">
+            AND fsc.supplier_contract_code like concat('%',#{page.supplierContractCode},'%')
+        </if>
+        <if test="page.supplierContractName != null and page.supplierContractName != ''">
+            AND fsc.supplier_contract_name like concat('%',#{page.supplierContractName},'%')
+        </if>
+        <if test="page.isFrameContract != null">
+            AND fsc.is_frame_contract = #{page.isFrameContract}
+        </if>
+        <if test="page.supplierName != null and page.supplierName != ''">
+            AND fsc.supplier_name like concat('%',#{page.supplierName},'%')
+        </if>
+        <if test="page.startDate != null and page.startDate.length > 0">
+            AND fsc.start_date BETWEEN #{page.startDate[0]} AND #{page.startDate[1]}
+        </if>
+        <if test="page.endDate != null and page.endDate.length > 0">
+            AND fsc.end_date BETWEEN #{page.endDate[0]} AND #{page.endDate[1]}
+        </if>
+        <if test="page.ownerEmployeeName != null and page.ownerEmployeeName != ''">
+            AND ei.name like concat('%',#{page.ownerEmployeeName},'%')
+        </if>
+        <if test="page.deptId != null">
+            AND fsc.dept_id = #{page.deptId}
+        </if>
+        <if test="page.contractStatus != null and page.contractStatus != ''">
+            AND fsc.contract_status = #{page.contractStatus}
+        </if>
+        <if test="page.closed != null">
+            AND fsc.closed = #{page.closed}
+        </if>
+        <if test="page.terminate != null">
+            AND fsc.terminate = #{page.terminate}
+        </if>
+    </select>
+    <select id="getPageList"
+            resultType="cn.iocoder.yudao.module.contract.controller.admin.suppliercontract.vo.SupplierContractRespVO">
+        SELECT
+            fsc.id,
+            fsc.supplier_contract_uuid,
+            fsc.supplier_contract_code,
+            fsc.supplier_contract_name,
+            fsc.is_frame_contract,
+               CASE
+                   WHEN fsc.is_frame_contract = 1 THEN '是'
+                   WHEN fsc.is_frame_contract = 0 THEN '否'
+                   ELSE '未知'
+               END AS isFrameContractDesc,
+            fsc.supplier_id,
+            fsc.supplier_name,
+            fsc.start_date,
+            fsc.end_date,
+            fsc.money,
+            fsc.owner_employee_id,
+               ei.name AS ownerEmployeeName,
+            fsc.dept_id,
+               sd.name AS deptName,
+            fsc.contract_status,
+                CASE
+                    WHEN fsc.contract_status = 0 THEN '未归档'
+                    WHEN fsc.contract_status = 1 THEN '已归档'
+                    WHEN fsc.contract_status = 2 THEN '已完结'
+                    ELSE '未知'
+                END AS contractStatusDesc,
+            fsc.closed,
+               CASE
+                    WHEN fsc.closed = 1 THEN '是'
+                    WHEN fsc.closed = 0 THEN '否'
+                    ELSE '未知'
+                END AS closedDesc,
+            fsc.close_reason,
+            fsc.terminate,
+               CASE
+                   WHEN fsc.terminate = 1 THEN '是'
+                   WHEN fsc.terminate = 0 THEN '否'
+                   ELSE '未知'
+               END AS terminateDesc,
+            fsc.terminate_date,
+            fsc.terminate_reason,
+            fsc.is_change,
+            fsc.remarks,
+            fsc.creator,
+               ei2.name AS creatorName,
+            fsc.create_time
+        FROM
+            finance_supplier_contract fsc
+                LEFT JOIN employee_info ei ON ei.id = fsc.owner_employee_id AND ei.deleted = 0
+                LEFT JOIN system_dept sd ON sd.id = fsc.dept_id AND sd.deleted = 0
+                LEFT JOIN employee_info ei2 ON ei2.id = fsc.creator AND ei2.deleted = 0
+        WHERE
+            fsc.deleted = 0
+        <if test="page.supplierContractCode != null and page.supplierContractCode != ''">
+            AND fsc.supplier_contract_code like concat('%',#{page.supplierContractCode},'%')
+        </if>
+        <if test="page.supplierContractName != null and page.supplierContractName != ''">
+            AND fsc.supplier_contract_name like concat('%',#{page.supplierContractName},'%')
+        </if>
+        <if test="page.isFrameContract != null">
+            AND fsc.is_frame_contract = #{page.isFrameContract}
+        </if>
+        <if test="page.supplierName != null and page.supplierName != ''">
+            AND fsc.supplier_name like concat('%',#{page.supplierName},'%')
+        </if>
+        <if test="page.startDate != null and page.startDate.length > 0">
+            AND fsc.start_date BETWEEN #{page.startDate[0]} AND #{page.startDate[1]}
+        </if>
+        <if test="page.endDate != null and page.endDate.length > 0">
+            AND fsc.end_date BETWEEN #{page.endDate[0]} AND #{page.endDate[1]}
+        </if>
+        <if test="page.ownerEmployeeName != null and page.ownerEmployeeName != ''">
+            AND ei.name like concat('%',#{page.ownerEmployeeName},'%')
+        </if>
+        <if test="page.deptId != null">
+            AND fsc.dept_id = #{page.deptId}
+        </if>
+        <if test="page.contractStatus != null and page.contractStatus != ''">
+            AND fsc.contract_status = #{page.contractStatus}
+        </if>
+        <if test="page.closed != null">
+            AND fsc.closed = #{page.closed}
+        </if>
+        <if test="page.terminate != null">
+            AND fsc.terminate = #{page.terminate}
+        </if>
+        ORDER BY
+            fsc.create_time DESC
+        <if test="page.pageSize != -1">
+            LIMIT #{page.pageNo}, #{page.pageSize}
+        </if>
+    </select>
+
+    <delete id="deleteSupplierContractOriginal">
+        DELETE
+        FROM
+            finance_supplier_contract
+        WHERE
+            id = #{id}
+            AND deleted = 0
+    </delete>
+</mapper>

+ 206 - 0
yudao-module-finance/yudao-module-contract-biz/src/test/java/cn/iocoder/yudao/module/contract/service/customercontract/CustomerContractServiceImplTest.java

@@ -0,0 +1,206 @@
+// package cn.iocoder.yudao.module.contract.service.customercontract;
+//
+// import org.junit.jupiter.api.Disabled;
+// import org.junit.jupiter.api.Test;
+// import org.springframework.boot.test.mock.mockito.MockBean;
+//
+// import javax.annotation.Resource;
+//
+// import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+//
+// import cn.iocoder.yudao.module.contract.controller.admin.customercontract.vo.*;
+// import cn.iocoder.yudao.module.contract.dal.dataobject.customercontract.CustomerContractDO;
+// import cn.iocoder.yudao.module.contract.dal.mysql.customercontract.CustomerContractMapper;
+// import cn.iocoder.yudao.framework.common.pojo.PageResult;
+//
+// import javax.annotation.Resource;
+// import org.springframework.context.annotation.Import;
+// import java.util.*;
+// import java.time.LocalDateTime;
+//
+// import static cn.hutool.core.util.RandomUtil.*;
+// import static cn.iocoder.yudao.module.contract.enums.ErrorCodeConstants.*;
+// import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
+// import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
+// import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
+// import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
+// import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
+// import static org.junit.jupiter.api.Assertions.*;
+// import static org.mockito.Mockito.*;
+//
+// /**
+//  * {@link CustomerContractServiceImpl} 的单元测试类
+//  *
+//  * @author dp
+//  */
+// @Import(CustomerContractServiceImpl.class)
+// public class CustomerContractServiceImplTest extends BaseDbUnitTest {
+//
+//     @Resource
+//     private CustomerContractServiceImpl customerContractService;
+//
+//     @Resource
+//     private CustomerContractMapper customerContractMapper;
+//
+//     @Test
+//     public void testCreateCustomerContract_success() {
+//         // 准备参数
+//         CustomerContractSaveReqVO createReqVO = randomPojo(CustomerContractSaveReqVO.class).setId(null);
+//
+//         // 调用
+//         Long customerContractId = customerContractService.createCustomerContract(createReqVO);
+//         // 断言
+//         assertNotNull(customerContractId);
+//         // 校验记录的属性是否正确
+//         CustomerContractDO customerContract = customerContractMapper.selectById(customerContractId);
+//         assertPojoEquals(createReqVO, customerContract, "id");
+//     }
+//
+//     @Test
+//     public void testUpdateCustomerContract_success() {
+//         // mock 数据
+//         CustomerContractDO dbCustomerContract = randomPojo(CustomerContractDO.class);
+//         customerContractMapper.insert(dbCustomerContract);// @Sql: 先插入出一条存在的数据
+//         // 准备参数
+//         CustomerContractSaveReqVO updateReqVO = randomPojo(CustomerContractSaveReqVO.class, o -> {
+//             o.setId(dbCustomerContract.getId()); // 设置更新的 ID
+//         });
+//
+//         // 调用
+//         customerContractService.updateCustomerContract(updateReqVO);
+//         // 校验是否更新正确
+//         CustomerContractDO customerContract = customerContractMapper.selectById(updateReqVO.getId()); // 获取最新的
+//         assertPojoEquals(updateReqVO, customerContract);
+//     }
+//
+//     @Test
+//     public void testUpdateCustomerContract_notExists() {
+//         // 准备参数
+//         CustomerContractSaveReqVO updateReqVO = randomPojo(CustomerContractSaveReqVO.class);
+//
+//         // 调用, 并断言异常
+//         assertServiceException(() -> customerContractService.updateCustomerContract(updateReqVO), CUSTOMER_CONTRACT_NOT_EXISTS);
+//     }
+//
+//     @Test
+//     public void testDeleteCustomerContract_success() {
+//         // mock 数据
+//         CustomerContractDO dbCustomerContract = randomPojo(CustomerContractDO.class);
+//         customerContractMapper.insert(dbCustomerContract);// @Sql: 先插入出一条存在的数据
+//         // 准备参数
+//         Long id = dbCustomerContract.getId();
+//
+//         // 调用
+//         customerContractService.deleteCustomerContract(id);
+//        // 校验数据不存在了
+//        assertNull(customerContractMapper.selectById(id));
+//     }
+//
+//     @Test
+//     public void testDeleteCustomerContract_notExists() {
+//         // 准备参数
+//         Long id = randomLongId();
+//
+//         // 调用, 并断言异常
+//         assertServiceException(() -> customerContractService.deleteCustomerContract(id), CUSTOMER_CONTRACT_NOT_EXISTS);
+//     }
+//
+//     @Test
+//     @Disabled  // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
+//     public void testGetCustomerContractPage() {
+//        // mock 数据
+//        CustomerContractDO dbCustomerContract = randomPojo(CustomerContractDO.class, o -> { // 等会查询到
+//            o.setCustomerContractUuid(null);
+//            o.setCustomerContractCode(null);
+//            o.setCustomerContractName(null);
+//            o.setIsFrameContract(null);
+//            o.setCustomerId(null);
+//            o.setCustomerName(null);
+//            o.setStartDate(null);
+//            o.setEndDate(null);
+//            o.setMoney(null);
+//            o.setOwnerEmployeeId(null);
+//            o.setDeptId(null);
+//            o.setContractStatus(null);
+//            o.setClosed(null);
+//            o.setCloseReason(null);
+//            o.setTerminate(null);
+//            o.setTerminateDate(null);
+//            o.setTerminateReason(null);
+//            o.setIsChange(null);
+//            o.setRemarks(null);
+//            o.setCreateTime(null);
+//        });
+//        customerContractMapper.insert(dbCustomerContract);
+//        // 测试 customerContractUuid 不匹配
+//        customerContractMapper.insert(cloneIgnoreId(dbCustomerContract, o -> o.setCustomerContractUuid(null)));
+//        // 测试 customerContractCode 不匹配
+//        customerContractMapper.insert(cloneIgnoreId(dbCustomerContract, o -> o.setCustomerContractCode(null)));
+//        // 测试 customerContractName 不匹配
+//        customerContractMapper.insert(cloneIgnoreId(dbCustomerContract, o -> o.setCustomerContractName(null)));
+//        // 测试 isFrameContract 不匹配
+//        customerContractMapper.insert(cloneIgnoreId(dbCustomerContract, o -> o.setIsFrameContract(null)));
+//        // 测试 customerId 不匹配
+//        customerContractMapper.insert(cloneIgnoreId(dbCustomerContract, o -> o.setCustomerId(null)));
+//        // 测试 customerName 不匹配
+//        customerContractMapper.insert(cloneIgnoreId(dbCustomerContract, o -> o.setCustomerName(null)));
+//        // 测试 startDate 不匹配
+//        customerContractMapper.insert(cloneIgnoreId(dbCustomerContract, o -> o.setStartDate(null)));
+//        // 测试 endDate 不匹配
+//        customerContractMapper.insert(cloneIgnoreId(dbCustomerContract, o -> o.setEndDate(null)));
+//        // 测试 money 不匹配
+//        customerContractMapper.insert(cloneIgnoreId(dbCustomerContract, o -> o.setMoney(null)));
+//        // 测试 ownerEmployeeId 不匹配
+//        customerContractMapper.insert(cloneIgnoreId(dbCustomerContract, o -> o.setOwnerEmployeeId(null)));
+//        // 测试 deptId 不匹配
+//        customerContractMapper.insert(cloneIgnoreId(dbCustomerContract, o -> o.setDeptId(null)));
+//        // 测试 contractStatus 不匹配
+//        customerContractMapper.insert(cloneIgnoreId(dbCustomerContract, o -> o.setContractStatus(null)));
+//        // 测试 closed 不匹配
+//        customerContractMapper.insert(cloneIgnoreId(dbCustomerContract, o -> o.setClosed(null)));
+//        // 测试 closeReason 不匹配
+//        customerContractMapper.insert(cloneIgnoreId(dbCustomerContract, o -> o.setCloseReason(null)));
+//        // 测试 terminate 不匹配
+//        customerContractMapper.insert(cloneIgnoreId(dbCustomerContract, o -> o.setTerminate(null)));
+//        // 测试 terminateDate 不匹配
+//        customerContractMapper.insert(cloneIgnoreId(dbCustomerContract, o -> o.setTerminateDate(null)));
+//        // 测试 terminateReason 不匹配
+//        customerContractMapper.insert(cloneIgnoreId(dbCustomerContract, o -> o.setTerminateReason(null)));
+//        // 测试 isChange 不匹配
+//        customerContractMapper.insert(cloneIgnoreId(dbCustomerContract, o -> o.setIsChange(null)));
+//        // 测试 remarks 不匹配
+//        customerContractMapper.insert(cloneIgnoreId(dbCustomerContract, o -> o.setRemarks(null)));
+//        // 测试 createTime 不匹配
+//        customerContractMapper.insert(cloneIgnoreId(dbCustomerContract, o -> o.setCreateTime(null)));
+//        // 准备参数
+//        CustomerContractPageReqVO reqVO = new CustomerContractPageReqVO();
+//        reqVO.setCustomerContractUuid(null);
+//        reqVO.setCustomerContractCode(null);
+//        reqVO.setCustomerContractName(null);
+//        reqVO.setIsFrameContract(null);
+//        reqVO.setCustomerId(null);
+//        reqVO.setCustomerName(null);
+//        reqVO.setStartDate(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+//        reqVO.setEndDate(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+//        reqVO.setMoney(null);
+//        reqVO.setOwnerEmployeeId(null);
+//        reqVO.setDeptId(null);
+//        reqVO.setContractStatus(null);
+//        reqVO.setClosed(null);
+//        reqVO.setCloseReason(null);
+//        reqVO.setTerminate(null);
+//        reqVO.setTerminateDate(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+//        reqVO.setTerminateReason(null);
+//        reqVO.setIsChange(null);
+//        reqVO.setRemarks(null);
+//        reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+//
+//        // 调用
+//        PageResult<CustomerContractDO> pageResult = customerContractService.getCustomerContractPage(reqVO);
+//        // 断言
+//        assertEquals(1, pageResult.getTotal());
+//        assertEquals(1, pageResult.getList().size());
+//        assertPojoEquals(dbCustomerContract, pageResult.getList().get(0));
+//     }
+//
+// }

+ 202 - 0
yudao-module-finance/yudao-module-contract-biz/src/test/java/cn/iocoder/yudao/module/contract/service/suppliercontract/SupplierContractServiceImplTest.java

@@ -0,0 +1,202 @@
+// package cn.iocoder.yudao.module.contract.service.suppliercontract;
+//
+// import org.junit.jupiter.api.Disabled;
+// import org.junit.jupiter.api.Test;
+// import org.springframework.boot.test.mock.mockito.MockBean;
+//
+// import javax.annotation.Resource;
+//
+// import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+//
+// import cn.iocoder.yudao.module.contract.controller.admin.suppliercontract.vo.*;
+// import cn.iocoder.yudao.module.contract.dal.dataobject.suppliercontract.SupplierContractDO;
+// import cn.iocoder.yudao.module.contract.dal.mysql.suppliercontract.SupplierContractMapper;
+// import cn.iocoder.yudao.framework.common.pojo.PageResult;
+//
+// import javax.annotation.Resource;
+// import org.springframework.context.annotation.Import;
+// import java.util.*;
+// import java.time.LocalDateTime;
+//
+// import static cn.hutool.core.util.RandomUtil.*;
+// import static cn.iocoder.yudao.module.contract.enums.ErrorCodeConstants.*;
+// import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
+// import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
+// import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
+// import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
+// import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
+// import static org.junit.jupiter.api.Assertions.*;
+// import static org.mockito.Mockito.*;
+//
+// /**
+//  * {@link SupplierContractServiceImpl} 的单元测试类
+//  *
+//  * @author dp
+//  */
+// @Import(SupplierContractServiceImpl.class)
+// public class SupplierContractServiceImplTest extends BaseDbUnitTest {
+//
+//     @Resource
+//     private SupplierContractServiceImpl supplierContractService;
+//
+//     @Resource
+//     private SupplierContractMapper supplierContractMapper;
+//
+//     @Test
+//     public void testCreateSupplierContract_success() {
+//         // 准备参数
+//         SupplierContractSaveReqVO createReqVO = randomPojo(SupplierContractSaveReqVO.class).setId(null);
+//
+//         // 调用
+//         Long supplierContractId = supplierContractService.createSupplierContract(createReqVO);
+//         // 断言
+//         assertNotNull(supplierContractId);
+//         // 校验记录的属性是否正确
+//         SupplierContractDO supplierContract = supplierContractMapper.selectById(supplierContractId);
+//         assertPojoEquals(createReqVO, supplierContract, "id");
+//     }
+//
+//     @Test
+//     public void testUpdateSupplierContract_success() {
+//         // mock 数据
+//         SupplierContractDO dbSupplierContract = randomPojo(SupplierContractDO.class);
+//         supplierContractMapper.insert(dbSupplierContract);// @Sql: 先插入出一条存在的数据
+//         // 准备参数
+//         SupplierContractSaveReqVO updateReqVO = randomPojo(SupplierContractSaveReqVO.class, o -> {
+//             o.setId(dbSupplierContract.getId()); // 设置更新的 ID
+//         });
+//
+//         // 调用
+//         supplierContractService.updateSupplierContract(updateReqVO);
+//         // 校验是否更新正确
+//         SupplierContractDO supplierContract = supplierContractMapper.selectById(updateReqVO.getId()); // 获取最新的
+//         assertPojoEquals(updateReqVO, supplierContract);
+//     }
+//
+//     @Test
+//     public void testUpdateSupplierContract_notExists() {
+//         // 准备参数
+//         SupplierContractSaveReqVO updateReqVO = randomPojo(SupplierContractSaveReqVO.class);
+//
+//         // 调用, 并断言异常
+//         assertServiceException(() -> supplierContractService.updateSupplierContract(updateReqVO), SUPPLIER_CONTRACT_NOT_EXISTS);
+//     }
+//
+//     @Test
+//     public void testDeleteSupplierContract_success() {
+//         // mock 数据
+//         SupplierContractDO dbSupplierContract = randomPojo(SupplierContractDO.class);
+//         supplierContractMapper.insert(dbSupplierContract);// @Sql: 先插入出一条存在的数据
+//         // 准备参数
+//         Long id = dbSupplierContract.getId();
+//
+//         // 调用
+//         supplierContractService.deleteSupplierContract(id);
+//        // 校验数据不存在了
+//        assertNull(supplierContractMapper.selectById(id));
+//     }
+//
+//     @Test
+//     public void testDeleteSupplierContract_notExists() {
+//         // 准备参数
+//         Long id = randomLongId();
+//
+//         // 调用, 并断言异常
+//         assertServiceException(() -> supplierContractService.deleteSupplierContract(id), SUPPLIER_CONTRACT_NOT_EXISTS);
+//     }
+//
+//     @Test
+//     @Disabled  // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
+//     public void testGetSupplierContractPage() {
+//        // mock 数据
+//        SupplierContractDO dbSupplierContract = randomPojo(SupplierContractDO.class, o -> { // 等会查询到
+//            o.setCode(null);
+//            o.setName(null);
+//            o.setIsFrameContract(null);
+//            o.setSupplierId(null);
+//            o.setSupplierName(null);
+//            o.setStartDate(null);
+//            o.setEndDate(null);
+//            o.setMoney(null);
+//            o.setOwnerEmployeeId(null);
+//            o.setDeptId(null);
+//            o.setStatus(null);
+//            o.setClosed(null);
+//            o.setCloseReason(null);
+//            o.setTerminated(null);
+//            o.setTerminateDate(null);
+//            o.setTerminateReason(null);
+//            o.setIsChange(null);
+//            o.setRemarks(null);
+//            o.setCreateTime(null);
+//        });
+//        supplierContractMapper.insert(dbSupplierContract);
+//        // 测试 code 不匹配
+//        supplierContractMapper.insert(cloneIgnoreId(dbSupplierContract, o -> o.setCode(null)));
+//        // 测试 name 不匹配
+//        supplierContractMapper.insert(cloneIgnoreId(dbSupplierContract, o -> o.setName(null)));
+//        // 测试 isFrameContract 不匹配
+//        supplierContractMapper.insert(cloneIgnoreId(dbSupplierContract, o -> o.setIsFrameContract(null)));
+//        // 测试 supplierId 不匹配
+//        supplierContractMapper.insert(cloneIgnoreId(dbSupplierContract, o -> o.setSupplierId(null)));
+//        // 测试 supplierName 不匹配
+//        supplierContractMapper.insert(cloneIgnoreId(dbSupplierContract, o -> o.setSupplierName(null)));
+//        // 测试 startDate 不匹配
+//        supplierContractMapper.insert(cloneIgnoreId(dbSupplierContract, o -> o.setStartDate(null)));
+//        // 测试 endDate 不匹配
+//        supplierContractMapper.insert(cloneIgnoreId(dbSupplierContract, o -> o.setEndDate(null)));
+//        // 测试 money 不匹配
+//        supplierContractMapper.insert(cloneIgnoreId(dbSupplierContract, o -> o.setMoney(null)));
+//        // 测试 ownerEmployeeId 不匹配
+//        supplierContractMapper.insert(cloneIgnoreId(dbSupplierContract, o -> o.setOwnerEmployeeId(null)));
+//        // 测试 deptId 不匹配
+//        supplierContractMapper.insert(cloneIgnoreId(dbSupplierContract, o -> o.setDeptId(null)));
+//        // 测试 status 不匹配
+//        supplierContractMapper.insert(cloneIgnoreId(dbSupplierContract, o -> o.setStatus(null)));
+//        // 测试 closed 不匹配
+//        supplierContractMapper.insert(cloneIgnoreId(dbSupplierContract, o -> o.setClosed(null)));
+//        // 测试 closeReason 不匹配
+//        supplierContractMapper.insert(cloneIgnoreId(dbSupplierContract, o -> o.setCloseReason(null)));
+//        // 测试 terminated 不匹配
+//        supplierContractMapper.insert(cloneIgnoreId(dbSupplierContract, o -> o.setTerminated(null)));
+//        // 测试 terminateDate 不匹配
+//        supplierContractMapper.insert(cloneIgnoreId(dbSupplierContract, o -> o.setTerminateDate(null)));
+//        // 测试 terminateReason 不匹配
+//        supplierContractMapper.insert(cloneIgnoreId(dbSupplierContract, o -> o.setTerminateReason(null)));
+//        // 测试 isChange 不匹配
+//        supplierContractMapper.insert(cloneIgnoreId(dbSupplierContract, o -> o.setIsChange(null)));
+//        // 测试 remarks 不匹配
+//        supplierContractMapper.insert(cloneIgnoreId(dbSupplierContract, o -> o.setRemarks(null)));
+//        // 测试 createTime 不匹配
+//        supplierContractMapper.insert(cloneIgnoreId(dbSupplierContract, o -> o.setCreateTime(null)));
+//        // 准备参数
+//        SupplierContractPageReqVO reqVO = new SupplierContractPageReqVO();
+//        reqVO.setCode(null);
+//        reqVO.setName(null);
+//        reqVO.setIsFrameContract(null);
+//        reqVO.setSupplierId(null);
+//        reqVO.setSupplierName(null);
+//        reqVO.setStartDate(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+//        reqVO.setEndDate(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+//        reqVO.setMoney(null);
+//        reqVO.setOwnerEmployeeId(null);
+//        reqVO.setDeptId(null);
+//        reqVO.setStatus(null);
+//        reqVO.setClosed(null);
+//        reqVO.setCloseReason(null);
+//        reqVO.setTerminated(null);
+//        reqVO.setTerminateDate(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+//        reqVO.setTerminateReason(null);
+//        reqVO.setIsChange(null);
+//        reqVO.setRemarks(null);
+//        reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+//
+//        // 调用
+//        PageResult<SupplierContractDO> pageResult = supplierContractService.getSupplierContractPage(reqVO);
+//        // 断言
+//        assertEquals(1, pageResult.getTotal());
+//        assertEquals(1, pageResult.getList().size());
+//        assertPojoEquals(dbSupplierContract, pageResult.getList().get(0));
+//     }
+//
+// }

+ 1 - 1
yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/service/expenseinfo/ExpenseInfoServiceImpl.java

@@ -221,7 +221,7 @@ public class ExpenseInfoServiceImpl implements ExpenseInfoService {
     @Override
     public PageResult<ExpenseInfoRespVO> getInfoPage(ExpenseInfoPageReqVO pageReqVO) {
 
-        pageReqVO.setPageNo(pageReqVO.getPageNo() - 1);
+        pageReqVO.setPageNo((pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize());
 
         long pageCount = 0;
         if (!Objects.equals(pageReqVO.getPageSize(), PageParam.PAGE_SIZE_NONE)) {

+ 4 - 0
yudao-module-personnel/yudao-module-employee-biz/src/main/java/cn/iocoder/yudao/module/employee/api/info/EmployeeApiImpl.java

@@ -16,6 +16,7 @@ import org.springframework.stereotype.Service;
 import javax.annotation.Resource;
 import java.util.Collection;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * 员工 API 实现类
@@ -46,6 +47,9 @@ public class EmployeeApiImpl implements EmployeeApi {
     @Override
     public EmployeeRespDTO getEmployeeByUserId(Long userId) {
         EmployeeInfoDO employeeInfoDO = infoService.getEmployeeByUserId(userId);
+        if (Objects.isNull(employeeInfoDO)) {
+            return null;
+        }
         EmployeeRespDTO employeeRespDTO = BeanUtils.toBean(employeeInfoDO, EmployeeRespDTO.class);
 
         // 根据员工ID查询员工当前的合同信息