Browse Source

1、添加财务系统
1、报销类型和费用项目代码生成

dongpo 7 months ago
parent
commit
b0f9142b70
25 changed files with 1329 additions and 0 deletions
  1. 1 0
      pom.xml
  2. 24 0
      yudao-module-finance/pom.xml
  3. 33 0
      yudao-module-finance/yudao-module-expense-api/pom.xml
  4. 11 0
      yudao-module-finance/yudao-module-expense-api/src/main/java/cn/iocoder/yudao/module/expense/enums/ErrorCodeConstants.java
  5. 76 0
      yudao-module-finance/yudao-module-expense-biz/pom.xml
  6. 93 0
      yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/controller/admin/expenseitem/ExpenseItemController.java
  7. 37 0
      yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/controller/admin/expenseitem/vo/ExpenseItemPageReqVO.java
  8. 44 0
      yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/controller/admin/expenseitem/vo/ExpenseItemRespVO.java
  9. 31 0
      yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/controller/admin/expenseitem/vo/ExpenseItemSaveReqVO.java
  10. 104 0
      yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/controller/admin/expensetype/ExpenseTypeController.java
  11. 31 0
      yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/controller/admin/expensetype/vo/ExpenseTypePageReqVO.java
  12. 36 0
      yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/controller/admin/expensetype/vo/ExpenseTypeRespVO.java
  13. 28 0
      yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/controller/admin/expensetype/vo/ExpenseTypeSaveReqVO.java
  14. 50 0
      yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/dal/dataobject/expenseitem/ExpenseItemDO.java
  15. 42 0
      yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/dal/dataobject/expensetype/ExpenseTypeDO.java
  16. 39 0
      yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/dal/mysql/expenseitem/ExpenseItemMapper.java
  17. 29 0
      yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/dal/mysql/expensetype/ExpenseTypeMapper.java
  18. 55 0
      yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/service/expenseitem/ExpenseItemService.java
  19. 71 0
      yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/service/expenseitem/ExpenseItemServiceImpl.java
  20. 67 0
      yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/service/expensetype/ExpenseTypeService.java
  21. 111 0
      yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/service/expensetype/ExpenseTypeServiceImpl.java
  22. 12 0
      yudao-module-finance/yudao-module-expense-biz/src/main/resources/mapper/expenseitem/ExpenseItemMapper.xml
  23. 12 0
      yudao-module-finance/yudao-module-expense-biz/src/main/resources/mapper/expensetype/ExpenseTypeMapper.xml
  24. 150 0
      yudao-module-finance/yudao-module-expense-biz/src/test/java/cn/iocoder/yudao/module/expense/service/expenseitem/ExpenseItemServiceImplTest.java
  25. 142 0
      yudao-module-finance/yudao-module-expense-biz/src/test/java/cn/iocoder/yudao/module/expense/service/expensetype/ExpenseTypeServiceImplTest.java

+ 1 - 0
pom.xml

@@ -24,6 +24,7 @@
 <!--        <module>yudao-module-mall</module>-->
 <!--        <module>yudao-module-crm</module>-->
 <!--        <module>yudao-module-erp</module>-->
+        <module>yudao-module-finance</module>
     </modules>
 
     <name>${project.artifactId}</name>

+ 24 - 0
yudao-module-finance/pom.xml

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>yudao</artifactId>
+        <groupId>cn.iocoder.boot</groupId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <modules>
+        <module>yudao-module-expense-api</module>
+        <module>yudao-module-expense-biz</module>
+    </modules>
+    <artifactId>yudao-module-finance</artifactId>
+    <packaging>pom</packaging>
+
+    <name>${project.artifactId}</name>
+    <description>
+        这里我们放财务系统的功能模块。
+    </description>
+
+
+</project>

+ 33 - 0
yudao-module-finance/yudao-module-expense-api/pom.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>yudao-module-finance</artifactId>
+        <groupId>cn.iocoder.boot</groupId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>jar</packaging>
+    <artifactId>yudao-module-expense-api</artifactId>
+    <name>${project.artifactId}</name>
+    <description>
+        expense 模块 API,暴露给其它模块调用
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-common</artifactId>
+        </dependency>
+
+        <!-- 参数校验 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+            <optional>true</optional>
+        </dependency>
+    </dependencies>
+
+
+</project>

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

@@ -0,0 +1,11 @@
+package cn.iocoder.yudao.module.expense.enums;
+
+import cn.iocoder.yudao.framework.common.exception.ErrorCode;
+
+public interface ErrorCodeConstants {
+
+    // ========== 报销类型信息 1_040_001_001 ==========
+    ErrorCode EXPENSE_TYPE_NOT_EXISTS = new ErrorCode(1_040_001_001, "报销类型信息不存在");
+    // ========== 报销费用项目信息 1_040_002_001 ==========
+    ErrorCode EXPENSE_ITEM_NOT_EXISTS = new ErrorCode(1_040_002_001, "报销费用项目信息不存在");
+}

+ 76 - 0
yudao-module-finance/yudao-module-expense-biz/pom.xml

@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>yudao-module-finance</artifactId>
+        <groupId>cn.iocoder.boot</groupId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>jar</packaging>
+
+    <artifactId>yudao-module-expense-biz</artifactId>
+    <name>${project.artifactId}</name>
+    <description>
+        expense 包下,我们放财务管理的功能模块。
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-module-expense-api</artifactId>
+            <version>${revision}</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-module-infra-api</artifactId>
+            <version>${revision}</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-module-system-api</artifactId>
+            <version>${revision}</version>
+        </dependency>
+
+        <!-- 业务组件 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-biz-data-permission</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
+        </dependency>
+
+        <!-- Web 相关 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-security</artifactId>
+        </dependency>
+
+        <!-- DB 相关 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
+        </dependency>
+
+        <!-- Test 测试相关 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-test</artifactId>
+        </dependency>
+
+        <!-- 工具类相关 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-excel</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

+ 93 - 0
yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/controller/admin/expenseitem/ExpenseItemController.java

@@ -0,0 +1,93 @@
+package cn.iocoder.yudao.module.expense.controller.admin.expenseitem;
+
+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.expense.controller.admin.expenseitem.vo.ExpenseItemPageReqVO;
+import cn.iocoder.yudao.module.expense.controller.admin.expenseitem.vo.ExpenseItemRespVO;
+import cn.iocoder.yudao.module.expense.controller.admin.expenseitem.vo.ExpenseItemSaveReqVO;
+import cn.iocoder.yudao.module.expense.dal.dataobject.expenseitem.ExpenseItemDO;
+import cn.iocoder.yudao.module.expense.service.expenseitem.ExpenseItemService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.List;
+
+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("/expense/item")
+@Validated
+public class ExpenseItemController {
+
+    @Resource
+    private ExpenseItemService itemService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建报销费用项目信息")
+    @PreAuthorize("@ss.hasPermission('expense:item:create')")
+    public CommonResult<Long> createItem(@Valid @RequestBody ExpenseItemSaveReqVO createReqVO) {
+        return success(itemService.createItem(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新报销费用项目信息")
+    @PreAuthorize("@ss.hasPermission('expense:item:update')")
+    public CommonResult<Boolean> updateItem(@Valid @RequestBody ExpenseItemSaveReqVO updateReqVO) {
+        itemService.updateItem(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除报销费用项目信息")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('expense:item:delete')")
+    public CommonResult<Boolean> deleteItem(@RequestParam("id") Long id) {
+        itemService.deleteItem(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得报销费用项目信息")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('expense:item:query')")
+    public CommonResult<ExpenseItemRespVO> getItem(@RequestParam("id") Long id) {
+        ExpenseItemDO item = itemService.getItem(id);
+        return success(BeanUtils.toBean(item, ExpenseItemRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得报销费用项目信息分页")
+    @PreAuthorize("@ss.hasPermission('expense:item:query')")
+    public CommonResult<PageResult<ExpenseItemRespVO>> getItemPage(@Valid ExpenseItemPageReqVO pageReqVO) {
+        PageResult<ExpenseItemDO> pageResult = itemService.getItemPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, ExpenseItemRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出报销费用项目信息 Excel")
+    @PreAuthorize("@ss.hasPermission('expense:item:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportItemExcel(@Valid ExpenseItemPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<ExpenseItemDO> list = itemService.getItemPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "报销费用项目信息.xls", "数据", ExpenseItemRespVO.class,
+                        BeanUtils.toBean(list, ExpenseItemRespVO.class));
+    }
+
+}

+ 37 - 0
yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/controller/admin/expenseitem/vo/ExpenseItemPageReqVO.java

@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.expense.controller.admin.expenseitem.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 报销费用项目信息分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class ExpenseItemPageReqVO extends PageParam {
+
+    @Schema(description = "报销类型主键id", example = "2556")
+    private Long expenseTypeId;
+
+    @Schema(description = "报销类型uuid", example = "14367")
+    private String expenseTypeUuid;
+
+    @Schema(description = "费用项目uuid", example = "10133")
+    private String expenseItemUuid;
+
+    @Schema(description = "费用项目", example = "芋艿")
+    private String name;
+
+    @Schema(description = "备注")
+    private String remarks;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 44 - 0
yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/controller/admin/expenseitem/vo/ExpenseItemRespVO.java

@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.expense.controller.admin.expenseitem.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import java.util.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+
+@Schema(description = "管理后台 - 报销费用项目信息 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class ExpenseItemRespVO {
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "4075")
+    @ExcelProperty("主键")
+    private Long id;
+
+    @Schema(description = "报销类型主键id", requiredMode = Schema.RequiredMode.REQUIRED, example = "2556")
+    @ExcelProperty("报销类型主键id")
+    private Long expenseTypeId;
+
+    @Schema(description = "报销类型uuid", example = "14367")
+    @ExcelProperty("报销类型uuid")
+    private String expenseTypeUuid;
+
+    @Schema(description = "费用项目uuid", example = "10133")
+    @ExcelProperty("费用项目uuid")
+    private String expenseItemUuid;
+
+    @Schema(description = "费用项目", example = "芋艿")
+    @ExcelProperty("费用项目")
+    private String name;
+
+    @Schema(description = "备注")
+    @ExcelProperty("备注")
+    private String remarks;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 31 - 0
yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/controller/admin/expenseitem/vo/ExpenseItemSaveReqVO.java

@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.module.expense.controller.admin.expenseitem.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import javax.validation.constraints.*;
+
+@Schema(description = "管理后台 - 报销费用项目信息新增/修改 Request VO")
+@Data
+public class ExpenseItemSaveReqVO {
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "4075")
+    private Long id;
+
+    @Schema(description = "报销类型主键id", requiredMode = Schema.RequiredMode.REQUIRED, example = "2556")
+    @NotNull(message = "报销类型主键id不能为空")
+    private Long expenseTypeId;
+
+    @Schema(description = "报销类型uuid", example = "14367")
+    private String expenseTypeUuid;
+
+    @Schema(description = "费用项目uuid", example = "10133")
+    private String expenseItemUuid;
+
+    @Schema(description = "费用项目", example = "芋艿")
+    private String name;
+
+    @Schema(description = "备注")
+    private String remarks;
+
+}

+ 104 - 0
yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/controller/admin/expensetype/ExpenseTypeController.java

@@ -0,0 +1,104 @@
+package cn.iocoder.yudao.module.expense.controller.admin.expensetype;
+
+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.expense.controller.admin.expensetype.vo.ExpenseTypePageReqVO;
+import cn.iocoder.yudao.module.expense.controller.admin.expensetype.vo.ExpenseTypeRespVO;
+import cn.iocoder.yudao.module.expense.controller.admin.expensetype.vo.ExpenseTypeSaveReqVO;
+import cn.iocoder.yudao.module.expense.dal.dataobject.expenseitem.ExpenseItemDO;
+import cn.iocoder.yudao.module.expense.dal.dataobject.expensetype.ExpenseTypeDO;
+import cn.iocoder.yudao.module.expense.service.expensetype.ExpenseTypeService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.List;
+
+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("/expense/type")
+@Validated
+public class ExpenseTypeController {
+
+    @Resource
+    private ExpenseTypeService typeService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建报销类型信息")
+    @PreAuthorize("@ss.hasPermission('expense:type:create')")
+    public CommonResult<Long> createType(@Valid @RequestBody ExpenseTypeSaveReqVO createReqVO) {
+        return success(typeService.createType(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新报销类型信息")
+    @PreAuthorize("@ss.hasPermission('expense:type:update')")
+    public CommonResult<Boolean> updateType(@Valid @RequestBody ExpenseTypeSaveReqVO updateReqVO) {
+        typeService.updateType(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除报销类型信息")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('expense:type:delete')")
+    public CommonResult<Boolean> deleteType(@RequestParam("id") Long id) {
+        typeService.deleteType(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得报销类型信息")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('expense:type:query')")
+    public CommonResult<ExpenseTypeRespVO> getType(@RequestParam("id") Long id) {
+        ExpenseTypeDO type = typeService.getType(id);
+        return success(BeanUtils.toBean(type, ExpenseTypeRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得报销类型信息分页")
+    @PreAuthorize("@ss.hasPermission('expense:type:query')")
+    public CommonResult<PageResult<ExpenseTypeRespVO>> getTypePage(@Valid ExpenseTypePageReqVO pageReqVO) {
+        PageResult<ExpenseTypeDO> pageResult = typeService.getTypePage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, ExpenseTypeRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出报销类型信息 Excel")
+    @PreAuthorize("@ss.hasPermission('expense:type:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportTypeExcel(@Valid ExpenseTypePageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<ExpenseTypeDO> list = typeService.getTypePage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "报销类型信息.xls", "数据", ExpenseTypeRespVO.class,
+                        BeanUtils.toBean(list, ExpenseTypeRespVO.class));
+    }
+
+    // ==================== 子表(报销费用项目信息) ====================
+
+    @GetMapping("/item/list-by-expense-type-id")
+    @Operation(summary = "获得报销费用项目信息列表")
+    @Parameter(name = "expenseTypeId", description = "报销类型主键id")
+    @PreAuthorize("@ss.hasPermission('expense:type:query')")
+    public CommonResult<List<ExpenseItemDO>> getItemListByExpenseTypeId(@RequestParam("expenseTypeId") Long expenseTypeId) {
+        return success(typeService.getItemListByExpenseTypeId(expenseTypeId));
+    }
+
+}

+ 31 - 0
yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/controller/admin/expensetype/vo/ExpenseTypePageReqVO.java

@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.module.expense.controller.admin.expensetype.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 报销类型信息分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class ExpenseTypePageReqVO extends PageParam {
+
+    @Schema(description = "uuid", example = "18264")
+    private String expenseTypeUuid;
+
+    @Schema(description = "报销类型", example = "芋艿")
+    private String name;
+
+    @Schema(description = "备注")
+    private String remarks;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 36 - 0
yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/controller/admin/expensetype/vo/ExpenseTypeRespVO.java

@@ -0,0 +1,36 @@
+package cn.iocoder.yudao.module.expense.controller.admin.expensetype.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import java.util.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+
+@Schema(description = "管理后台 - 报销类型信息 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class ExpenseTypeRespVO {
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "21030")
+    @ExcelProperty("主键")
+    private Long id;
+
+    @Schema(description = "uuid", example = "18264")
+    @ExcelProperty("uuid")
+    private String expenseTypeUuid;
+
+    @Schema(description = "报销类型", example = "芋艿")
+    @ExcelProperty("报销类型")
+    private String name;
+
+    @Schema(description = "备注")
+    @ExcelProperty("备注")
+    private String remarks;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 28 - 0
yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/controller/admin/expensetype/vo/ExpenseTypeSaveReqVO.java

@@ -0,0 +1,28 @@
+package cn.iocoder.yudao.module.expense.controller.admin.expensetype.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import javax.validation.constraints.*;
+import cn.iocoder.yudao.module.expense.dal.dataobject.expenseitem.ExpenseItemDO;
+
+@Schema(description = "管理后台 - 报销类型信息新增/修改 Request VO")
+@Data
+public class ExpenseTypeSaveReqVO {
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "21030")
+    private Long id;
+
+    @Schema(description = "uuid", example = "18264")
+    private String expenseTypeUuid;
+
+    @Schema(description = "报销类型", example = "芋艿")
+    private String name;
+
+    @Schema(description = "备注")
+    private String remarks;
+
+    @Schema(description = "报销费用项目信息列表")
+    private List<ExpenseItemDO> items;
+
+}

+ 50 - 0
yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/dal/dataobject/expenseitem/ExpenseItemDO.java

@@ -0,0 +1,50 @@
+package cn.iocoder.yudao.module.expense.dal.dataobject.expenseitem;
+
+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.*;
+
+/**
+ * 报销费用项目信息 DO
+ *
+ * @author dp
+ */
+@TableName("finance_expense_item")
+@KeySequence("finance_expense_item_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ExpenseItemDO extends BaseDO {
+
+    /**
+     * 主键
+     */
+    @TableId
+    private Long id;
+    /**
+     * 报销类型主键id
+     */
+    private Long expenseTypeId;
+    /**
+     * 报销类型uuid
+     */
+    private String expenseTypeUuid;
+    /**
+     * 费用项目uuid
+     */
+    private String expenseItemUuid;
+    /**
+     * 费用项目
+     */
+    private String name;
+    /**
+     * 备注
+     */
+    private String remarks;
+
+}

+ 42 - 0
yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/dal/dataobject/expensetype/ExpenseTypeDO.java

@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.module.expense.dal.dataobject.expensetype;
+
+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.*;
+
+/**
+ * 报销类型信息 DO
+ *
+ * @author dp
+ */
+@TableName("finance_expense_type")
+@KeySequence("finance_expense_type_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ExpenseTypeDO extends BaseDO {
+
+    /**
+     * 主键
+     */
+    @TableId
+    private Long id;
+    /**
+     * uuid
+     */
+    private String expenseTypeUuid;
+    /**
+     * 报销类型
+     */
+    private String name;
+    /**
+     * 备注
+     */
+    private String remarks;
+
+}

+ 39 - 0
yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/dal/mysql/expenseitem/ExpenseItemMapper.java

@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.expense.dal.mysql.expenseitem;
+
+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.expense.controller.admin.expenseitem.vo.ExpenseItemPageReqVO;
+import cn.iocoder.yudao.module.expense.dal.dataobject.expenseitem.ExpenseItemDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * 报销费用项目信息 Mapper
+ *
+ * @author dp
+ */
+@Mapper
+public interface ExpenseItemMapper extends BaseMapperX<ExpenseItemDO> {
+
+    default PageResult<ExpenseItemDO> selectPage(ExpenseItemPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<ExpenseItemDO>()
+                .eqIfPresent(ExpenseItemDO::getExpenseTypeId, reqVO.getExpenseTypeId())
+                .eqIfPresent(ExpenseItemDO::getExpenseTypeUuid, reqVO.getExpenseTypeUuid())
+                .eqIfPresent(ExpenseItemDO::getExpenseItemUuid, reqVO.getExpenseItemUuid())
+                .likeIfPresent(ExpenseItemDO::getName, reqVO.getName())
+                .eqIfPresent(ExpenseItemDO::getRemarks, reqVO.getRemarks())
+                .betweenIfPresent(ExpenseItemDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(ExpenseItemDO::getId));
+    }
+
+    default List<ExpenseItemDO> selectListByExpenseTypeId(Long expenseTypeId) {
+        return selectList(ExpenseItemDO::getExpenseTypeId, expenseTypeId);
+    }
+
+    default int deleteByExpenseTypeId(Long expenseTypeId) {
+        return delete(ExpenseItemDO::getExpenseTypeId, expenseTypeId);
+    }
+
+}

+ 29 - 0
yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/dal/mysql/expensetype/ExpenseTypeMapper.java

@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.module.expense.dal.mysql.expensetype;
+
+import java.util.*;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.expense.dal.dataobject.expensetype.ExpenseTypeDO;
+import org.apache.ibatis.annotations.Mapper;
+import cn.iocoder.yudao.module.expense.controller.admin.expensetype.vo.*;
+
+/**
+ * 报销类型信息 Mapper
+ *
+ * @author dp
+ */
+@Mapper
+public interface ExpenseTypeMapper extends BaseMapperX<ExpenseTypeDO> {
+
+    default PageResult<ExpenseTypeDO> selectPage(ExpenseTypePageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<ExpenseTypeDO>()
+                .eqIfPresent(ExpenseTypeDO::getExpenseTypeUuid, reqVO.getExpenseTypeUuid())
+                .likeIfPresent(ExpenseTypeDO::getName, reqVO.getName())
+                .eqIfPresent(ExpenseTypeDO::getRemarks, reqVO.getRemarks())
+                .betweenIfPresent(ExpenseTypeDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(ExpenseTypeDO::getId));
+    }
+
+}

+ 55 - 0
yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/service/expenseitem/ExpenseItemService.java

@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.expense.service.expenseitem;
+
+import java.util.*;
+import javax.validation.*;
+import cn.iocoder.yudao.module.expense.controller.admin.expenseitem.vo.*;
+import cn.iocoder.yudao.module.expense.dal.dataobject.expenseitem.ExpenseItemDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+
+/**
+ * 报销费用项目信息 Service 接口
+ *
+ * @author dp
+ */
+public interface ExpenseItemService {
+
+    /**
+     * 创建报销费用项目信息
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createItem(@Valid ExpenseItemSaveReqVO createReqVO);
+
+    /**
+     * 更新报销费用项目信息
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateItem(@Valid ExpenseItemSaveReqVO updateReqVO);
+
+    /**
+     * 删除报销费用项目信息
+     *
+     * @param id 编号
+     */
+    void deleteItem(Long id);
+
+    /**
+     * 获得报销费用项目信息
+     *
+     * @param id 编号
+     * @return 报销费用项目信息
+     */
+    ExpenseItemDO getItem(Long id);
+
+    /**
+     * 获得报销费用项目信息分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 报销费用项目信息分页
+     */
+    PageResult<ExpenseItemDO> getItemPage(ExpenseItemPageReqVO pageReqVO);
+
+}

+ 71 - 0
yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/service/expenseitem/ExpenseItemServiceImpl.java

@@ -0,0 +1,71 @@
+package cn.iocoder.yudao.module.expense.service.expenseitem;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.expense.controller.admin.expenseitem.vo.ExpenseItemPageReqVO;
+import cn.iocoder.yudao.module.expense.controller.admin.expenseitem.vo.ExpenseItemSaveReqVO;
+import cn.iocoder.yudao.module.expense.dal.dataobject.expenseitem.ExpenseItemDO;
+import cn.iocoder.yudao.module.expense.dal.mysql.expenseitem.ExpenseItemMapper;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.expense.enums.ErrorCodeConstants.EXPENSE_ITEM_NOT_EXISTS;
+
+/**
+ * 报销费用项目信息 Service 实现类
+ *
+ * @author dp
+ */
+@Service
+@Validated
+public class ExpenseItemServiceImpl implements ExpenseItemService {
+
+    @Resource
+    private ExpenseItemMapper itemMapper;
+
+    @Override
+    public Long createItem(ExpenseItemSaveReqVO createReqVO) {
+        // 插入
+        ExpenseItemDO item = BeanUtils.toBean(createReqVO, ExpenseItemDO.class);
+        itemMapper.insert(item);
+        // 返回
+        return item.getId();
+    }
+
+    @Override
+    public void updateItem(ExpenseItemSaveReqVO updateReqVO) {
+        // 校验存在
+        validateItemExists(updateReqVO.getId());
+        // 更新
+        ExpenseItemDO updateObj = BeanUtils.toBean(updateReqVO, ExpenseItemDO.class);
+        itemMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteItem(Long id) {
+        // 校验存在
+        validateItemExists(id);
+        // 删除
+        itemMapper.deleteById(id);
+    }
+
+    private void validateItemExists(Long id) {
+        if (itemMapper.selectById(id) == null) {
+            throw exception(EXPENSE_ITEM_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public ExpenseItemDO getItem(Long id) {
+        return itemMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<ExpenseItemDO> getItemPage(ExpenseItemPageReqVO pageReqVO) {
+        return itemMapper.selectPage(pageReqVO);
+    }
+
+}

+ 67 - 0
yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/service/expensetype/ExpenseTypeService.java

@@ -0,0 +1,67 @@
+package cn.iocoder.yudao.module.expense.service.expensetype;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.expense.controller.admin.expensetype.vo.ExpenseTypePageReqVO;
+import cn.iocoder.yudao.module.expense.controller.admin.expensetype.vo.ExpenseTypeSaveReqVO;
+import cn.iocoder.yudao.module.expense.dal.dataobject.expenseitem.ExpenseItemDO;
+import cn.iocoder.yudao.module.expense.dal.dataobject.expensetype.ExpenseTypeDO;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * 报销类型信息 Service 接口
+ *
+ * @author dp
+ */
+public interface ExpenseTypeService {
+
+    /**
+     * 创建报销类型信息
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createType(@Valid ExpenseTypeSaveReqVO createReqVO);
+
+    /**
+     * 更新报销类型信息
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateType(@Valid ExpenseTypeSaveReqVO updateReqVO);
+
+    /**
+     * 删除报销类型信息
+     *
+     * @param id 编号
+     */
+    void deleteType(Long id);
+
+    /**
+     * 获得报销类型信息
+     *
+     * @param id 编号
+     * @return 报销类型信息
+     */
+    ExpenseTypeDO getType(Long id);
+
+    /**
+     * 获得报销类型信息分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 报销类型信息分页
+     */
+    PageResult<ExpenseTypeDO> getTypePage(ExpenseTypePageReqVO pageReqVO);
+
+    // ==================== 子表(报销费用项目信息) ====================
+
+    /**
+     * 获得报销费用项目信息列表
+     *
+     * @param expenseTypeId 报销类型主键id
+     * @return 报销费用项目信息列表
+     */
+    List<ExpenseItemDO> getItemListByExpenseTypeId(Long expenseTypeId);
+
+}

+ 111 - 0
yudao-module-finance/yudao-module-expense-biz/src/main/java/cn/iocoder/yudao/module/expense/service/expensetype/ExpenseTypeServiceImpl.java

@@ -0,0 +1,111 @@
+package cn.iocoder.yudao.module.expense.service.expensetype;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.expense.controller.admin.expensetype.vo.ExpenseTypePageReqVO;
+import cn.iocoder.yudao.module.expense.controller.admin.expensetype.vo.ExpenseTypeSaveReqVO;
+import cn.iocoder.yudao.module.expense.dal.dataobject.expenseitem.ExpenseItemDO;
+import cn.iocoder.yudao.module.expense.dal.dataobject.expensetype.ExpenseTypeDO;
+import cn.iocoder.yudao.module.expense.dal.mysql.expenseitem.ExpenseItemMapper;
+import cn.iocoder.yudao.module.expense.dal.mysql.expensetype.ExpenseTypeMapper;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.expense.enums.ErrorCodeConstants.EXPENSE_TYPE_NOT_EXISTS;
+
+/**
+ * 报销类型信息 Service 实现类
+ *
+ * @author dp
+ */
+@Service
+@Validated
+public class ExpenseTypeServiceImpl implements ExpenseTypeService {
+
+    @Resource
+    private ExpenseTypeMapper typeMapper;
+    @Resource
+    private ExpenseItemMapper itemMapper;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Long createType(ExpenseTypeSaveReqVO createReqVO) {
+        // 插入
+        ExpenseTypeDO type = BeanUtils.toBean(createReqVO, ExpenseTypeDO.class);
+        typeMapper.insert(type);
+
+        // 插入子表
+        createItemList(type.getId(), createReqVO.getItems());
+        // 返回
+        return type.getId();
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void updateType(ExpenseTypeSaveReqVO updateReqVO) {
+        // 校验存在
+        validateTypeExists(updateReqVO.getId());
+        // 更新
+        ExpenseTypeDO updateObj = BeanUtils.toBean(updateReqVO, ExpenseTypeDO.class);
+        typeMapper.updateById(updateObj);
+
+        // 更新子表
+        updateItemList(updateReqVO.getId(), updateReqVO.getItems());
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deleteType(Long id) {
+        // 校验存在
+        validateTypeExists(id);
+        // 删除
+        typeMapper.deleteById(id);
+
+        // 删除子表
+        deleteItemByExpenseTypeId(id);
+    }
+
+    private void validateTypeExists(Long id) {
+        if (typeMapper.selectById(id) == null) {
+            throw exception(EXPENSE_TYPE_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public ExpenseTypeDO getType(Long id) {
+        return typeMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<ExpenseTypeDO> getTypePage(ExpenseTypePageReqVO pageReqVO) {
+        return typeMapper.selectPage(pageReqVO);
+    }
+
+    // ==================== 子表(报销费用项目信息) ====================
+
+    @Override
+    public List<ExpenseItemDO> getItemListByExpenseTypeId(Long expenseTypeId) {
+        return itemMapper.selectListByExpenseTypeId(expenseTypeId);
+    }
+
+    private void createItemList(Long expenseTypeId, List<ExpenseItemDO> list) {
+        list.forEach(o -> o.setExpenseTypeId(expenseTypeId));
+        itemMapper.insertBatch(list);
+    }
+
+    private void updateItemList(Long expenseTypeId, List<ExpenseItemDO> list) {
+        deleteItemByExpenseTypeId(expenseTypeId);
+		list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下:1)id 冲突;2)updateTime 不更新
+        createItemList(expenseTypeId, list);
+    }
+
+    private void deleteItemByExpenseTypeId(Long expenseTypeId) {
+        itemMapper.deleteByExpenseTypeId(expenseTypeId);
+    }
+
+}

+ 12 - 0
yudao-module-finance/yudao-module-expense-biz/src/main/resources/mapper/expenseitem/ExpenseItemMapper.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.expense.dal.mysql.expenseitem.ExpenseItemMapper">
+
+    <!--
+        一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
+        无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
+        代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
+        文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
+     -->
+
+</mapper>

+ 12 - 0
yudao-module-finance/yudao-module-expense-biz/src/main/resources/mapper/expensetype/ExpenseTypeMapper.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.expense.dal.mysql.expensetype.ExpenseTypeMapper">
+
+    <!--
+        一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
+        无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
+        代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
+        文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
+     -->
+
+</mapper>

+ 150 - 0
yudao-module-finance/yudao-module-expense-biz/src/test/java/cn/iocoder/yudao/module/expense/service/expenseitem/ExpenseItemServiceImplTest.java

@@ -0,0 +1,150 @@
+// package cn.iocoder.yudao.module.expense.service.expenseitem;
+//
+// 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.expense.controller.admin.expenseitem.vo.*;
+// import cn.iocoder.yudao.module.expense.dal.dataobject.expenseitem.ExpenseItemDO;
+// import cn.iocoder.yudao.module.expense.dal.mysql.expenseitem.ExpenseItemMapper;
+// 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.expense.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 ExpenseItemServiceImpl} 的单元测试类
+//  *
+//  * @author dp
+//  */
+// @Import(ExpenseItemServiceImpl.class)
+// public class ExpenseItemServiceImplTest extends BaseDbUnitTest {
+//
+//     @Resource
+//     private ExpenseItemServiceImpl itemService;
+//
+//     @Resource
+//     private ExpenseItemMapper itemMapper;
+//
+//     @Test
+//     public void testCreateItem_success() {
+//         // 准备参数
+//         ExpenseItemSaveReqVO createReqVO = randomPojo(ExpenseItemSaveReqVO.class).setId(null);
+//
+//         // 调用
+//         Long itemId = itemService.createItem(createReqVO);
+//         // 断言
+//         assertNotNull(itemId);
+//         // 校验记录的属性是否正确
+//         ExpenseItemDO item = itemMapper.selectById(itemId);
+//         assertPojoEquals(createReqVO, item, "id");
+//     }
+//
+//     @Test
+//     public void testUpdateItem_success() {
+//         // mock 数据
+//         ExpenseItemDO dbItem = randomPojo(ExpenseItemDO.class);
+//         itemMapper.insert(dbItem);// @Sql: 先插入出一条存在的数据
+//         // 准备参数
+//         ExpenseItemSaveReqVO updateReqVO = randomPojo(ExpenseItemSaveReqVO.class, o -> {
+//             o.setId(dbItem.getId()); // 设置更新的 ID
+//         });
+//
+//         // 调用
+//         itemService.updateItem(updateReqVO);
+//         // 校验是否更新正确
+//         ExpenseItemDO item = itemMapper.selectById(updateReqVO.getId()); // 获取最新的
+//         assertPojoEquals(updateReqVO, item);
+//     }
+//
+//     @Test
+//     public void testUpdateItem_notExists() {
+//         // 准备参数
+//         ExpenseItemSaveReqVO updateReqVO = randomPojo(ExpenseItemSaveReqVO.class);
+//
+//         // 调用, 并断言异常
+//         assertServiceException(() -> itemService.updateItem(updateReqVO), EXPENSE_ITEM_NOT_EXISTS);
+//     }
+//
+//     @Test
+//     public void testDeleteItem_success() {
+//         // mock 数据
+//         ExpenseItemDO dbItem = randomPojo(ExpenseItemDO.class);
+//         itemMapper.insert(dbItem);// @Sql: 先插入出一条存在的数据
+//         // 准备参数
+//         Long id = dbItem.getId();
+//
+//         // 调用
+//         itemService.deleteItem(id);
+//        // 校验数据不存在了
+//        assertNull(itemMapper.selectById(id));
+//     }
+//
+//     @Test
+//     public void testDeleteItem_notExists() {
+//         // 准备参数
+//         Long id = randomLongId();
+//
+//         // 调用, 并断言异常
+//         assertServiceException(() -> itemService.deleteItem(id), ITEM_NOT_EXISTS);
+//     }
+//
+//     @Test
+//     @Disabled  // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
+//     public void testGetItemPage() {
+//        // mock 数据
+//        ExpenseItemDO dbItem = randomPojo(ExpenseItemDO.class, o -> { // 等会查询到
+//            o.setExpenseTypeId(null);
+//            o.setExpenseTypeUuid(null);
+//            o.setExpenseItemUuid(null);
+//            o.setName(null);
+//            o.setRemarks(null);
+//            o.setCreateTime(null);
+//        });
+//        itemMapper.insert(dbItem);
+//        // 测试 expenseTypeId 不匹配
+//        itemMapper.insert(cloneIgnoreId(dbItem, o -> o.setExpenseTypeId(null)));
+//        // 测试 expenseTypeUuid 不匹配
+//        itemMapper.insert(cloneIgnoreId(dbItem, o -> o.setExpenseTypeUuid(null)));
+//        // 测试 expenseItemUuid 不匹配
+//        itemMapper.insert(cloneIgnoreId(dbItem, o -> o.setExpenseItemUuid(null)));
+//        // 测试 name 不匹配
+//        itemMapper.insert(cloneIgnoreId(dbItem, o -> o.setName(null)));
+//        // 测试 remarks 不匹配
+//        itemMapper.insert(cloneIgnoreId(dbItem, o -> o.setRemarks(null)));
+//        // 测试 createTime 不匹配
+//        itemMapper.insert(cloneIgnoreId(dbItem, o -> o.setCreateTime(null)));
+//        // 准备参数
+//        ExpenseItemPageReqVO reqVO = new ExpenseItemPageReqVO();
+//        reqVO.setExpenseTypeId(null);
+//        reqVO.setExpenseTypeUuid(null);
+//        reqVO.setExpenseItemUuid(null);
+//        reqVO.setName(null);
+//        reqVO.setRemarks(null);
+//        reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+//
+//        // 调用
+//        PageResult<ExpenseItemDO> pageResult = itemService.getItemPage(reqVO);
+//        // 断言
+//        assertEquals(1, pageResult.getTotal());
+//        assertEquals(1, pageResult.getList().size());
+//        assertPojoEquals(dbItem, pageResult.getList().get(0));
+//     }
+//
+// }

+ 142 - 0
yudao-module-finance/yudao-module-expense-biz/src/test/java/cn/iocoder/yudao/module/expense/service/expensetype/ExpenseTypeServiceImplTest.java

@@ -0,0 +1,142 @@
+// package cn.iocoder.yudao.module.expense.service.expensetype;
+//
+// 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.expense.controller.admin.expensetype.vo.*;
+// import cn.iocoder.yudao.module.expense.dal.dataobject.expensetype.ExpenseTypeDO;
+// import cn.iocoder.yudao.module.expense.dal.mysql.expensetype.ExpenseTypeMapper;
+// 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.expense.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 ExpenseTypeServiceImpl} 的单元测试类
+//  *
+//  * @author dp
+//  */
+// @Import(ExpenseTypeServiceImpl.class)
+// public class ExpenseTypeServiceImplTest extends BaseDbUnitTest {
+//
+//     @Resource
+//     private ExpenseTypeServiceImpl typeService;
+//
+//     @Resource
+//     private ExpenseTypeMapper typeMapper;
+//
+//     @Test
+//     public void testCreateType_success() {
+//         // 准备参数
+//         ExpenseTypeSaveReqVO createReqVO = randomPojo(ExpenseTypeSaveReqVO.class).setId(null);
+//
+//         // 调用
+//         Long typeId = typeService.createType(createReqVO);
+//         // 断言
+//         assertNotNull(typeId);
+//         // 校验记录的属性是否正确
+//         ExpenseTypeDO type = typeMapper.selectById(typeId);
+//         assertPojoEquals(createReqVO, type, "id");
+//     }
+//
+//     @Test
+//     public void testUpdateType_success() {
+//         // mock 数据
+//         ExpenseTypeDO dbType = randomPojo(ExpenseTypeDO.class);
+//         typeMapper.insert(dbType);// @Sql: 先插入出一条存在的数据
+//         // 准备参数
+//         ExpenseTypeSaveReqVO updateReqVO = randomPojo(ExpenseTypeSaveReqVO.class, o -> {
+//             o.setId(dbType.getId()); // 设置更新的 ID
+//         });
+//
+//         // 调用
+//         typeService.updateType(updateReqVO);
+//         // 校验是否更新正确
+//         ExpenseTypeDO type = typeMapper.selectById(updateReqVO.getId()); // 获取最新的
+//         assertPojoEquals(updateReqVO, type);
+//     }
+//
+//     @Test
+//     public void testUpdateType_notExists() {
+//         // 准备参数
+//         ExpenseTypeSaveReqVO updateReqVO = randomPojo(ExpenseTypeSaveReqVO.class);
+//
+//         // 调用, 并断言异常
+//         assertServiceException(() -> typeService.updateType(updateReqVO), EXPENSE_TYPE_NOT_EXISTS);
+//     }
+//
+//     @Test
+//     public void testDeleteType_success() {
+//         // mock 数据
+//         ExpenseTypeDO dbType = randomPojo(ExpenseTypeDO.class);
+//         typeMapper.insert(dbType);// @Sql: 先插入出一条存在的数据
+//         // 准备参数
+//         Long id = dbType.getId();
+//
+//         // 调用
+//         typeService.deleteType(id);
+//        // 校验数据不存在了
+//        assertNull(typeMapper.selectById(id));
+//     }
+//
+//     @Test
+//     public void testDeleteType_notExists() {
+//         // 准备参数
+//         Long id = randomLongId();
+//
+//         // 调用, 并断言异常
+//         assertServiceException(() -> typeService.deleteType(id), TYPE_NOT_EXISTS);
+//     }
+//
+//     @Test
+//     @Disabled  // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
+//     public void testGetTypePage() {
+//        // mock 数据
+//        ExpenseTypeDO dbType = randomPojo(ExpenseTypeDO.class, o -> { // 等会查询到
+//            o.setExpenseTypeUuid(null);
+//            o.setName(null);
+//            o.setRemarks(null);
+//            o.setCreateTime(null);
+//        });
+//        typeMapper.insert(dbType);
+//        // 测试 expenseTypeUuid 不匹配
+//        typeMapper.insert(cloneIgnoreId(dbType, o -> o.setExpenseTypeUuid(null)));
+//        // 测试 name 不匹配
+//        typeMapper.insert(cloneIgnoreId(dbType, o -> o.setName(null)));
+//        // 测试 remarks 不匹配
+//        typeMapper.insert(cloneIgnoreId(dbType, o -> o.setRemarks(null)));
+//        // 测试 createTime 不匹配
+//        typeMapper.insert(cloneIgnoreId(dbType, o -> o.setCreateTime(null)));
+//        // 准备参数
+//        ExpenseTypePageReqVO reqVO = new ExpenseTypePageReqVO();
+//        reqVO.setExpenseTypeUuid(null);
+//        reqVO.setName(null);
+//        reqVO.setRemarks(null);
+//        reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+//
+//        // 调用
+//        PageResult<ExpenseTypeDO> pageResult = typeService.getTypePage(reqVO);
+//        // 断言
+//        assertEquals(1, pageResult.getTotal());
+//        assertEquals(1, pageResult.getList().size());
+//        assertPojoEquals(dbType, pageResult.getList().get(0));
+//     }
+//
+// }