修改代码
This commit is contained in:
64
lyzsys-module-tjt/pom.xml
Normal file
64
lyzsys-module-tjt/pom.xml
Normal file
@@ -0,0 +1,64 @@
|
||||
<?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>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>lyzsys</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>lyzsys-module-tjt</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>
|
||||
tjt 模块,承载特建投设计产值统计业务。
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>lyzsys-module-infra</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>lyzsys-spring-boot-starter-biz-tenant</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>lyzsys-spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>lyzsys-spring-boot-starter-mybatis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>lyzsys-spring-boot-starter-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>lyzsys-spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>lyzsys-spring-boot-starter-excel</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,43 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.controller.admin.outputsplit;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.outputsplit.vo.ProjectOutputSplitRespVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.outputsplit.vo.ProjectOutputSplitSaveReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.service.outputsplit.ProjectOutputSplitService;
|
||||
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.validation.Valid;
|
||||
|
||||
import static cn.iocoder.lyzsys.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 特建投页面4拆分比例")
|
||||
@RestController
|
||||
@RequestMapping("/tjt/output-split")
|
||||
@Validated
|
||||
public class ProjectOutputSplitController {
|
||||
|
||||
@Resource
|
||||
private ProjectOutputSplitService projectOutputSplitService;
|
||||
|
||||
@GetMapping("/get-by-planning")
|
||||
@Operation(summary = "根据合约规划获得页面4拆分比例")
|
||||
@Parameter(name = "planningId", description = "合约规划 ID", required = true, example = "1")
|
||||
@PreAuthorize("@ss.hasPermission('tjt:output-split:query')")
|
||||
public CommonResult<ProjectOutputSplitRespVO> getProjectOutputSplitByPlanningId(@RequestParam("planningId") Long planningId) {
|
||||
return success(projectOutputSplitService.getProjectOutputSplit(planningId));
|
||||
}
|
||||
|
||||
@PutMapping("/save")
|
||||
@Operation(summary = "保存页面4拆分比例")
|
||||
@PreAuthorize("@ss.hasPermission('tjt:output-split:update')")
|
||||
public CommonResult<Long> saveProjectOutputSplit(@Valid @RequestBody ProjectOutputSplitSaveReqVO reqVO) {
|
||||
return success(projectOutputSplitService.saveProjectOutputSplit(reqVO));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.controller.admin.outputsplit.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Schema(description = "管理后台 - 页面4拆分比例 Response VO")
|
||||
@Data
|
||||
public class ProjectOutputSplitRespVO {
|
||||
|
||||
@Schema(description = "页面4拆分 ID", example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "项目 ID", example = "1")
|
||||
private Long projectId;
|
||||
|
||||
@Schema(description = "合约规划 ID", example = "1")
|
||||
private Long planningId;
|
||||
|
||||
@Schema(description = "项目名称")
|
||||
private String projectName;
|
||||
|
||||
@Schema(description = "规划内容")
|
||||
private String planningContent;
|
||||
|
||||
@Schema(description = "年度")
|
||||
private Integer year;
|
||||
|
||||
@Schema(description = "考核产值")
|
||||
private BigDecimal assessmentOutputValue;
|
||||
|
||||
@Schema(description = "项目经理")
|
||||
private String projectManagerName;
|
||||
|
||||
@Schema(description = "项目负责人")
|
||||
private String engineeringLeaderName;
|
||||
|
||||
@Schema(description = "项目经理比例")
|
||||
private BigDecimal projectManagerRatio;
|
||||
|
||||
@Schema(description = "项目经理金额")
|
||||
private BigDecimal projectManagerAmount;
|
||||
|
||||
@Schema(description = "项目负责人比例")
|
||||
private BigDecimal engineeringLeaderRatio;
|
||||
|
||||
@Schema(description = "项目负责人金额")
|
||||
private BigDecimal engineeringLeaderAmount;
|
||||
|
||||
@Schema(description = "专业所比例")
|
||||
private BigDecimal officeRatio;
|
||||
|
||||
@Schema(description = "专业所金额")
|
||||
private BigDecimal officeAmount;
|
||||
|
||||
@Schema(description = "建筑专业比例")
|
||||
private BigDecimal archRatio;
|
||||
|
||||
@Schema(description = "建筑专业金额")
|
||||
private BigDecimal archAmount;
|
||||
|
||||
@Schema(description = "装修专业比例")
|
||||
private BigDecimal decorRatio;
|
||||
|
||||
@Schema(description = "装修专业金额")
|
||||
private BigDecimal decorAmount;
|
||||
|
||||
@Schema(description = "结构专业比例")
|
||||
private BigDecimal structRatio;
|
||||
|
||||
@Schema(description = "结构专业金额")
|
||||
private BigDecimal structAmount;
|
||||
|
||||
@Schema(description = "水专业比例")
|
||||
private BigDecimal waterRatio;
|
||||
|
||||
@Schema(description = "水专业金额")
|
||||
private BigDecimal waterAmount;
|
||||
|
||||
@Schema(description = "电气专业比例")
|
||||
private BigDecimal elecRatio;
|
||||
|
||||
@Schema(description = "电气专业金额")
|
||||
private BigDecimal elecAmount;
|
||||
|
||||
@Schema(description = "暖通专业比例")
|
||||
private BigDecimal hvacRatio;
|
||||
|
||||
@Schema(description = "暖通专业金额")
|
||||
private BigDecimal hvacAmount;
|
||||
|
||||
@Schema(description = "数字化设计专业比例")
|
||||
private BigDecimal digitalRatio;
|
||||
|
||||
@Schema(description = "数字化设计专业金额")
|
||||
private BigDecimal digitalAmount;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.controller.admin.outputsplit.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Schema(description = "管理后台 - 页面4拆分比例新增/修改 Request VO")
|
||||
@Data
|
||||
public class ProjectOutputSplitSaveReqVO {
|
||||
|
||||
@Schema(description = "合同规划 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "合同规划 ID 不能为空")
|
||||
private Long planningId;
|
||||
|
||||
@Schema(description = "项目经理比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "0.0200")
|
||||
@NotNull(message = "项目经理比例不能为空")
|
||||
private BigDecimal projectManagerRatio;
|
||||
|
||||
@Schema(description = "项目负责人比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "0.0300")
|
||||
@NotNull(message = "项目负责人比例不能为空")
|
||||
private BigDecimal engineeringLeaderRatio;
|
||||
|
||||
@Schema(description = "专业所比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "0.9500")
|
||||
@NotNull(message = "专业所比例不能为空")
|
||||
private BigDecimal officeRatio;
|
||||
|
||||
@Schema(description = "建筑专业比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "0.5000")
|
||||
@NotNull(message = "建筑专业比例不能为空")
|
||||
private BigDecimal archRatio;
|
||||
|
||||
@Schema(description = "装修专业比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "0.0000")
|
||||
@NotNull(message = "装修专业比例不能为空")
|
||||
private BigDecimal decorRatio;
|
||||
|
||||
@Schema(description = "结构专业比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "0.2000")
|
||||
@NotNull(message = "结构专业比例不能为空")
|
||||
private BigDecimal structRatio;
|
||||
|
||||
@Schema(description = "水专业比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "0.1000")
|
||||
@NotNull(message = "水专业比例不能为空")
|
||||
private BigDecimal waterRatio;
|
||||
|
||||
@Schema(description = "电气专业比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "0.1000")
|
||||
@NotNull(message = "电气专业比例不能为空")
|
||||
private BigDecimal elecRatio;
|
||||
|
||||
@Schema(description = "暖通专业比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "0.0500")
|
||||
@NotNull(message = "暖通专业比例不能为空")
|
||||
private BigDecimal hvacRatio;
|
||||
|
||||
@Schema(description = "数字化设计专业比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "0.0500")
|
||||
@NotNull(message = "数字化设计专业比例不能为空")
|
||||
private BigDecimal digitalRatio;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.controller.admin.planning;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.lyzsys.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.lyzsys.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.lyzsys.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.planning.vo.ProjectPlanningPageReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.planning.vo.ProjectPlanningRespVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.planning.vo.ProjectPlanningSaveReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planning.ProjectPlanningDO;
|
||||
import cn.iocoder.lyzsys.module.tjt.service.planning.ProjectPlanningService;
|
||||
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.validation.Valid;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.lyzsys.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 特建投合约规划")
|
||||
@RestController
|
||||
@RequestMapping("/tjt/planning")
|
||||
@Validated
|
||||
public class ProjectPlanningController {
|
||||
|
||||
private static final int RATIO_SCALE = 4;
|
||||
private static final BigDecimal ZERO_RATIO = BigDecimal.ZERO.setScale(RATIO_SCALE, RoundingMode.HALF_UP);
|
||||
|
||||
@Resource
|
||||
private ProjectPlanningService projectPlanningService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建合约规划")
|
||||
@PreAuthorize("@ss.hasPermission('tjt:planning:create')")
|
||||
public CommonResult<Long> createProjectPlanning(@Valid @RequestBody ProjectPlanningSaveReqVO createReqVO) {
|
||||
return success(projectPlanningService.createProjectPlanning(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "修改合约规划")
|
||||
@PreAuthorize("@ss.hasPermission('tjt:planning:update')")
|
||||
public CommonResult<Boolean> updateProjectPlanning(@Valid @RequestBody ProjectPlanningSaveReqVO updateReqVO) {
|
||||
projectPlanningService.updateProjectPlanning(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除合约规划")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1")
|
||||
@PreAuthorize("@ss.hasPermission('tjt:planning:delete')")
|
||||
public CommonResult<Boolean> deleteProjectPlanning(@RequestParam("id") Long id) {
|
||||
projectPlanningService.deleteProjectPlanning(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-list")
|
||||
@Operation(summary = "批量删除合约规划")
|
||||
@Parameter(name = "ids", description = "编号列表", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('tjt:planning:delete')")
|
||||
public CommonResult<Boolean> deleteProjectPlanningList(@RequestParam("ids") List<Long> ids) {
|
||||
projectPlanningService.deleteProjectPlanningList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得合约规划分页")
|
||||
@PreAuthorize("@ss.hasPermission('tjt:planning:query')")
|
||||
public CommonResult<PageResult<ProjectPlanningRespVO>> getProjectPlanningPage(@Valid ProjectPlanningPageReqVO pageReqVO) {
|
||||
PageResult<ProjectPlanningDO> pageResult = projectPlanningService.getProjectPlanningPage(pageReqVO);
|
||||
Map<Long, BigDecimal> allocatedAmountMap = projectPlanningService.getAllocatedAmountMap(
|
||||
CollectionUtils.convertSet(pageResult.getList(), ProjectPlanningDO::getId));
|
||||
return success(BeanUtils.toBean(pageResult, ProjectPlanningRespVO.class,
|
||||
respVO -> fillDistributionSummary(respVO, allocatedAmountMap)));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得合约规划详情")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1")
|
||||
@PreAuthorize("@ss.hasPermission('tjt:planning:query')")
|
||||
public CommonResult<ProjectPlanningRespVO> getProjectPlanning(@RequestParam("id") Long id) {
|
||||
ProjectPlanningDO planning = projectPlanningService.getProjectPlanning(id);
|
||||
if (planning == null) {
|
||||
return success(null);
|
||||
}
|
||||
Map<Long, BigDecimal> allocatedAmountMap = projectPlanningService.getAllocatedAmountMap(
|
||||
Collections.singleton(planning.getId()));
|
||||
return success(BeanUtils.toBean(planning, ProjectPlanningRespVO.class,
|
||||
respVO -> fillDistributionSummary(respVO, allocatedAmountMap)));
|
||||
}
|
||||
|
||||
@GetMapping("/list-by-project")
|
||||
@Operation(summary = "根据项目获得合约规划列表")
|
||||
@Parameter(name = "projectId", description = "项目 ID", required = true, example = "1")
|
||||
@PreAuthorize("@ss.hasPermission('tjt:planning:query')")
|
||||
public CommonResult<List<ProjectPlanningRespVO>> getProjectPlanningListByProjectId(@RequestParam("projectId") Long projectId) {
|
||||
List<ProjectPlanningDO> list = projectPlanningService.getProjectPlanningListByProjectId(projectId);
|
||||
Map<Long, BigDecimal> allocatedAmountMap = projectPlanningService.getAllocatedAmountMap(
|
||||
CollectionUtils.convertSet(list, ProjectPlanningDO::getId));
|
||||
return success(BeanUtils.toBean(list, ProjectPlanningRespVO.class,
|
||||
respVO -> fillDistributionSummary(respVO, allocatedAmountMap)));
|
||||
}
|
||||
|
||||
private void fillDistributionSummary(ProjectPlanningRespVO respVO, Map<Long, BigDecimal> allocatedAmountMap) {
|
||||
BigDecimal allocatedRatio = allocatedAmountMap.getOrDefault(respVO.getId(), ZERO_RATIO);
|
||||
BigDecimal totalDistributionAmount = respVO.getTotalDistributionAmount() == null
|
||||
? ZERO_RATIO : respVO.getTotalDistributionAmount().setScale(RATIO_SCALE, RoundingMode.HALF_UP);
|
||||
BigDecimal allocatedAmount = totalDistributionAmount.multiply(allocatedRatio)
|
||||
.setScale(RATIO_SCALE, RoundingMode.HALF_UP);
|
||||
respVO.setAllocatedAmount(allocatedAmount);
|
||||
respVO.setPendingAmount(totalDistributionAmount.subtract(allocatedAmount)
|
||||
.setScale(RATIO_SCALE, RoundingMode.HALF_UP));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.controller.admin.planning.vo;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.lyzsys.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 合约规划分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ProjectPlanningPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "项目 ID", example = "1")
|
||||
private Long projectId;
|
||||
|
||||
@Schema(description = "归属类型", example = "专业所")
|
||||
private String ownershipType;
|
||||
|
||||
@Schema(description = "产值计算方式", example = "指导价法")
|
||||
private String calculationMethod;
|
||||
|
||||
@Schema(description = "规划内容,模糊匹配", example = "建筑")
|
||||
private String planningContent;
|
||||
|
||||
@Schema(description = "开始年度", example = "2026")
|
||||
private Integer planningStartYear;
|
||||
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.controller.admin.planning.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 合约规划 Response VO")
|
||||
@Data
|
||||
public class ProjectPlanningRespVO {
|
||||
|
||||
@Schema(description = "合约规划 ID", example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "项目 ID", example = "1")
|
||||
private Long projectId;
|
||||
|
||||
@Schema(description = "归属类型")
|
||||
private String ownershipType;
|
||||
|
||||
@Schema(description = "产值计算方式")
|
||||
private String calculationMethod;
|
||||
|
||||
@Schema(description = "规划内容")
|
||||
private String planningContent;
|
||||
|
||||
@Schema(description = "规划金额")
|
||||
private BigDecimal planningAmount;
|
||||
|
||||
@Schema(description = "管理费费率")
|
||||
private BigDecimal managementFeeRate;
|
||||
|
||||
@Schema(description = "管理费")
|
||||
private BigDecimal managementFee;
|
||||
|
||||
@Schema(description = "实施团队")
|
||||
private String implementationTeam;
|
||||
|
||||
@Schema(description = "开始年度")
|
||||
private Integer planningStartYear;
|
||||
|
||||
@Schema(description = "面积")
|
||||
private BigDecimal planningArea;
|
||||
|
||||
@Schema(description = "设计阶段")
|
||||
private String designStage;
|
||||
|
||||
@Schema(description = "本次设计阶段比例")
|
||||
private BigDecimal currentDesignStageRatio;
|
||||
|
||||
@Schema(description = "审核审定是否外包")
|
||||
private Boolean reviewOutsourceFlag;
|
||||
|
||||
@Schema(description = "审核审定占比")
|
||||
private BigDecimal reviewOutsourceRatio;
|
||||
|
||||
@Schema(description = "总分配比例")
|
||||
private BigDecimal totalDistributionAmount;
|
||||
|
||||
@Schema(description = "已分配比例")
|
||||
private BigDecimal allocatedAmount;
|
||||
|
||||
@Schema(description = "待分配比例")
|
||||
private BigDecimal pendingAmount;
|
||||
|
||||
@Schema(description = "Planning progress remark")
|
||||
private String progressRemark;
|
||||
|
||||
@Schema(description = "楼栋数或户型数")
|
||||
private Integer buildingOrUnitCount;
|
||||
|
||||
@Schema(description = "套图系数,保留两位小数")
|
||||
private BigDecimal drawingSetFactor;
|
||||
|
||||
@Schema(description = "规模系数,保留两位小数")
|
||||
private BigDecimal scaleFactor;
|
||||
|
||||
@Schema(description = "修改系数,保留两位小数")
|
||||
private BigDecimal modificationFactor;
|
||||
|
||||
@Schema(description = "复杂系数/复杂等级,按比例值返回(100%=1.0000)")
|
||||
private BigDecimal complexityFactor;
|
||||
|
||||
@Schema(description = "内部指导单价(元/㎡)")
|
||||
private BigDecimal internalGuidanceUnitPrice;
|
||||
|
||||
@Schema(description = "虚拟产值计算方式")
|
||||
private String virtualCalculationMethod;
|
||||
|
||||
@Schema(description = "工日")
|
||||
private BigDecimal workingDayCount;
|
||||
|
||||
@Schema(description = "工日单价")
|
||||
private BigDecimal workingDayUnitPrice;
|
||||
|
||||
@Schema(description = "指导单价")
|
||||
private BigDecimal guidanceUnitPrice;
|
||||
|
||||
@Schema(description = "指导总价")
|
||||
private BigDecimal guidanceTotalPrice;
|
||||
|
||||
@Schema(description = "虚拟总价")
|
||||
private BigDecimal virtualTotalPrice;
|
||||
|
||||
@Schema(description = "产值计算比例")
|
||||
private BigDecimal calculationRatio;
|
||||
|
||||
@Schema(description = "合同单价(元/㎡)")
|
||||
private BigDecimal contractUnitPrice;
|
||||
|
||||
@Schema(description = "合计调整系数")
|
||||
private BigDecimal totalAdjustmentFactor;
|
||||
|
||||
@Schema(description = "考核面积")
|
||||
private BigDecimal assessmentArea;
|
||||
|
||||
@Schema(description = "虚拟产值")
|
||||
private BigDecimal virtualOutputValue;
|
||||
|
||||
@Schema(description = "考核产值")
|
||||
private BigDecimal assessmentOutputValue;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.controller.admin.planning.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Schema(description = "管理后台 - 合约规划新增/修改 Request VO")
|
||||
@Data
|
||||
public class ProjectPlanningSaveReqVO {
|
||||
|
||||
@Schema(description = "合约规划 ID", example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "项目 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "项目 ID 不能为空")
|
||||
private Long projectId;
|
||||
|
||||
@Schema(description = "归属类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "专业所")
|
||||
@NotBlank(message = "归属类型不能为空")
|
||||
@Size(max = 20, message = "归属类型长度不能超过 20 个字符")
|
||||
private String ownershipType;
|
||||
|
||||
@Schema(description = "产值计算方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "指导价法")
|
||||
@NotBlank(message = "产值计算方式不能为空")
|
||||
@Size(max = 30, message = "产值计算方式长度不能超过 30 个字符")
|
||||
private String calculationMethod;
|
||||
|
||||
@Schema(description = "规划内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "建筑设计")
|
||||
@NotBlank(message = "规划内容不能为空")
|
||||
@Size(max = 255, message = "规划内容长度不能超过 255 个字符")
|
||||
private String planningContent;
|
||||
|
||||
@Schema(description = "规划金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "500000")
|
||||
@NotNull(message = "规划金额不能为空")
|
||||
private BigDecimal planningAmount;
|
||||
|
||||
@Schema(description = "管理费费率", requiredMode = Schema.RequiredMode.REQUIRED, example = "0.0500")
|
||||
@NotNull(message = "管理费费率不能为空")
|
||||
private BigDecimal managementFeeRate;
|
||||
|
||||
@Schema(description = "实施团队", example = "建筑一所")
|
||||
@Size(max = 100, message = "实施团队长度不能超过 100 个字符")
|
||||
private String implementationTeam;
|
||||
|
||||
@Schema(description = "开始年度", example = "2026")
|
||||
private Integer planningStartYear;
|
||||
|
||||
@Schema(description = "面积", example = "30000")
|
||||
private BigDecimal planningArea;
|
||||
|
||||
@Schema(description = "设计阶段", example = "方案设计")
|
||||
@Size(max = 50, message = "设计阶段长度不能超过 50 个字符")
|
||||
private String designStage;
|
||||
|
||||
@Schema(description = "本次设计阶段比例", example = "0.3000")
|
||||
private BigDecimal currentDesignStageRatio;
|
||||
|
||||
@Schema(description = "审核审定是否外包", example = "false")
|
||||
private Boolean reviewOutsourceFlag;
|
||||
|
||||
@Schema(description = "审核审定占比", example = "0.0600")
|
||||
private BigDecimal reviewOutsourceRatio;
|
||||
|
||||
@Schema(description = "总分配比例", example = "1.0000")
|
||||
private BigDecimal totalDistributionAmount;
|
||||
|
||||
@Schema(description = "Planning progress remark", example = "Q1 extraction arrangement")
|
||||
@Size(max = 500, message = "Progress remark length must be within 500 characters")
|
||||
private String progressRemark;
|
||||
|
||||
@Schema(description = "楼栋数或户型数", example = "10")
|
||||
private Integer buildingOrUnitCount;
|
||||
|
||||
@Schema(description = "套图系数,保留两位小数", example = "1.00")
|
||||
private BigDecimal drawingSetFactor;
|
||||
|
||||
@Schema(description = "规模系数,保留两位小数", example = "1.00")
|
||||
private BigDecimal scaleFactor;
|
||||
|
||||
@Schema(description = "修改系数,保留两位小数", example = "1.00")
|
||||
private BigDecimal modificationFactor;
|
||||
|
||||
@Schema(description = "复杂系数/复杂等级,按比例值存储(100%=1.0000)", example = "1.0000")
|
||||
private BigDecimal complexityFactor;
|
||||
|
||||
@Schema(description = "内部指导单价(元/㎡)", example = "80.00")
|
||||
private BigDecimal internalGuidanceUnitPrice;
|
||||
|
||||
@Schema(description = "虚拟产值计算方式", example = "工日法")
|
||||
@Size(max = 30, message = "虚拟产值计算方式长度不能超过 30 个字符")
|
||||
private String virtualCalculationMethod;
|
||||
|
||||
@Schema(description = "工日", example = "100")
|
||||
private BigDecimal workingDayCount;
|
||||
|
||||
@Schema(description = "工日单价", example = "1000.00")
|
||||
private BigDecimal workingDayUnitPrice;
|
||||
|
||||
@Schema(description = "指导单价", example = "88.00")
|
||||
private BigDecimal guidanceUnitPrice;
|
||||
|
||||
@Schema(description = "指导总价", example = "880000.00")
|
||||
private BigDecimal guidanceTotalPrice;
|
||||
|
||||
@Schema(description = "虚拟总价", example = "600000.00")
|
||||
private BigDecimal virtualTotalPrice;
|
||||
|
||||
@Schema(description = "产值计算比例", example = "0.0800")
|
||||
private BigDecimal calculationRatio;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.controller.admin.planningquarter;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.lyzsys.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.planningquarter.vo.ProjectPlanningQuarterRespVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.planningquarter.vo.ProjectPlanningQuarterSaveReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planningquarter.ProjectPlanningQuarterDO;
|
||||
import cn.iocoder.lyzsys.module.tjt.service.planningquarter.ProjectPlanningQuarterService;
|
||||
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.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.lyzsys.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 特建投季度分配")
|
||||
@RestController
|
||||
@RequestMapping("/tjt/planning-quarter")
|
||||
@Validated
|
||||
public class ProjectPlanningQuarterController {
|
||||
|
||||
@Resource
|
||||
private ProjectPlanningQuarterService projectPlanningQuarterService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建季度分配")
|
||||
@PreAuthorize("@ss.hasPermission('tjt:planning-quarter:create')")
|
||||
public CommonResult<Long> createProjectPlanningQuarter(@Valid @RequestBody ProjectPlanningQuarterSaveReqVO createReqVO) {
|
||||
return success(projectPlanningQuarterService.createProjectPlanningQuarter(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "修改季度分配")
|
||||
@PreAuthorize("@ss.hasPermission('tjt:planning-quarter:update')")
|
||||
public CommonResult<Boolean> updateProjectPlanningQuarter(@Valid @RequestBody ProjectPlanningQuarterSaveReqVO updateReqVO) {
|
||||
projectPlanningQuarterService.updateProjectPlanningQuarter(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除季度分配")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1")
|
||||
@PreAuthorize("@ss.hasPermission('tjt:planning-quarter:delete')")
|
||||
public CommonResult<Boolean> deleteProjectPlanningQuarter(@RequestParam("id") Long id) {
|
||||
projectPlanningQuarterService.deleteProjectPlanningQuarter(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-list")
|
||||
@Operation(summary = "批量删除季度分配")
|
||||
@Parameter(name = "ids", description = "编号列表", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('tjt:planning-quarter:delete')")
|
||||
public CommonResult<Boolean> deleteProjectPlanningQuarterList(@RequestParam("ids") List<Long> ids) {
|
||||
projectPlanningQuarterService.deleteProjectPlanningQuarterList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得季度分配详情")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1")
|
||||
@PreAuthorize("@ss.hasPermission('tjt:planning-quarter:query')")
|
||||
public CommonResult<ProjectPlanningQuarterRespVO> getProjectPlanningQuarter(@RequestParam("id") Long id) {
|
||||
ProjectPlanningQuarterDO quarter = projectPlanningQuarterService.getProjectPlanningQuarter(id);
|
||||
return success(BeanUtils.toBean(quarter, ProjectPlanningQuarterRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/list-by-planning")
|
||||
@Operation(summary = "根据合约规划获得季度分配列表")
|
||||
@Parameter(name = "planningId", description = "合约规划 ID", required = true, example = "1")
|
||||
@PreAuthorize("@ss.hasPermission('tjt:planning-quarter:query')")
|
||||
public CommonResult<List<ProjectPlanningQuarterRespVO>> getProjectPlanningQuarterListByPlanningId(
|
||||
@RequestParam("planningId") Long planningId) {
|
||||
List<ProjectPlanningQuarterDO> list = projectPlanningQuarterService.getProjectPlanningQuarterListByPlanningId(planningId);
|
||||
return success(BeanUtils.toBean(list, ProjectPlanningQuarterRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.controller.admin.planningquarter.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 季度分配 Response VO")
|
||||
@Data
|
||||
public class ProjectPlanningQuarterRespVO {
|
||||
|
||||
@Schema(description = "季度分配 ID", example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "合约规划 ID", example = "1")
|
||||
private Long planningId;
|
||||
|
||||
@Schema(description = "分配年度")
|
||||
private Integer distributionYear;
|
||||
|
||||
@Schema(description = "季度")
|
||||
private Integer quarterNo;
|
||||
|
||||
@Schema(description = "分配比例")
|
||||
private BigDecimal distributionRatio;
|
||||
|
||||
@Schema(description = "分配金额")
|
||||
private BigDecimal distributionAmount;
|
||||
|
||||
@Schema(description = "提取进度备注")
|
||||
private String progressRemark;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.controller.admin.planningquarter.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.Max;
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Schema(description = "管理后台 - 季度分配新增/修改 Request VO")
|
||||
@Data
|
||||
public class ProjectPlanningQuarterSaveReqVO {
|
||||
|
||||
@Schema(description = "季度分配 ID", example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "合约规划 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "合约规划 ID 不能为空")
|
||||
private Long planningId;
|
||||
|
||||
@Schema(description = "分配年度", requiredMode = Schema.RequiredMode.REQUIRED, example = "2026")
|
||||
@NotNull(message = "分配年度不能为空")
|
||||
private Integer distributionYear;
|
||||
|
||||
@Schema(description = "季度", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "季度不能为空")
|
||||
@Min(value = 1, message = "季度必须在 1 到 4 之间")
|
||||
@Max(value = 4, message = "季度必须在 1 到 4 之间")
|
||||
private Integer quarterNo;
|
||||
|
||||
@Schema(description = "分配比例", example = "0.2500")
|
||||
private BigDecimal distributionRatio;
|
||||
|
||||
@Schema(description = "提取进度备注", example = "Q1 提取")
|
||||
@Size(max = 500, message = "提取进度备注长度不能超过 500 个字符")
|
||||
private String progressRemark;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.controller.admin.profit;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.lyzsys.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.profit.vo.ProjectProfitPageReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.profit.vo.ProjectProfitRespVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.service.profit.ProjectProfitService;
|
||||
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.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
|
||||
import static cn.iocoder.lyzsys.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 特建投项目盈亏")
|
||||
@RestController
|
||||
@RequestMapping("/tjt/profit")
|
||||
@Validated
|
||||
public class ProjectProfitController {
|
||||
|
||||
@Resource
|
||||
private ProjectProfitService projectProfitService;
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得项目盈亏详情")
|
||||
@Parameter(name = "projectId", description = "项目 ID", required = true, example = "1")
|
||||
@PreAuthorize("@ss.hasPermission('tjt:profit:query')")
|
||||
public CommonResult<ProjectProfitRespVO> getProjectProfit(@RequestParam("projectId") Long projectId) {
|
||||
return success(projectProfitService.getProjectProfit(projectId));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得项目盈亏分页")
|
||||
@PreAuthorize("@ss.hasPermission('tjt:profit:query')")
|
||||
public CommonResult<PageResult<ProjectProfitRespVO>> getProjectProfitPage(@Valid ProjectProfitPageReqVO pageReqVO) {
|
||||
return success(projectProfitService.getProjectProfitPage(pageReqVO));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.controller.admin.profit.vo;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.lyzsys.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 项目盈亏分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ProjectProfitPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "工程名称,模糊匹配", example = "设计")
|
||||
private String projectName;
|
||||
|
||||
@Schema(description = "是否签订合同", example = "true")
|
||||
private Boolean contractSignedFlag;
|
||||
|
||||
@Schema(description = "项目开始年度", example = "2026")
|
||||
private Integer projectStartYear;
|
||||
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.controller.admin.profit.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 项目盈亏 Response VO")
|
||||
@Data
|
||||
public class ProjectProfitRespVO {
|
||||
|
||||
@Schema(description = "项目 ID", example = "1")
|
||||
private Long projectId;
|
||||
|
||||
@Schema(description = "工程名称")
|
||||
private String projectName;
|
||||
|
||||
@Schema(description = "是否签订合同")
|
||||
private Boolean contractSignedFlag;
|
||||
|
||||
@Schema(description = "合同金额")
|
||||
private BigDecimal contractAmount;
|
||||
|
||||
@Schema(description = "最终结算金额")
|
||||
private BigDecimal finalSettlementAmount;
|
||||
|
||||
@Schema(description = "综合所协作金额")
|
||||
private BigDecimal comprehensivePlanningAmount;
|
||||
|
||||
@Schema(description = "专业分包金额")
|
||||
private BigDecimal subcontractPlanningAmount;
|
||||
|
||||
@Schema(description = "专业所产值")
|
||||
private BigDecimal majorOutputValue;
|
||||
|
||||
@Schema(description = "预计 K 值")
|
||||
private BigDecimal expectedKValue;
|
||||
|
||||
@Schema(description = "专业所预计绩效")
|
||||
private BigDecimal majorExpectedPerformance;
|
||||
|
||||
@Schema(description = "盈亏值")
|
||||
private BigDecimal profitLossValue;
|
||||
|
||||
@Schema(description = "盈亏百分比")
|
||||
private BigDecimal profitLossRate;
|
||||
|
||||
@Schema(description = "项目开始年度")
|
||||
private Integer projectStartYear;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.controller.admin.project;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.lyzsys.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.lyzsys.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.project.vo.ProjectPageReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.project.vo.ProjectRespVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.project.vo.ProjectSaveReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.project.ProjectDO;
|
||||
import cn.iocoder.lyzsys.module.tjt.service.project.ProjectService;
|
||||
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.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.lyzsys.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 特建投项目")
|
||||
@RestController
|
||||
@RequestMapping("/tjt/project")
|
||||
@Validated
|
||||
public class ProjectController {
|
||||
|
||||
@Resource
|
||||
private ProjectService projectService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建项目")
|
||||
@PreAuthorize("@ss.hasPermission('tjt:project:create')")
|
||||
public CommonResult<Long> createProject(@Valid @RequestBody ProjectSaveReqVO createReqVO) {
|
||||
return success(projectService.createProject(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "修改项目")
|
||||
@PreAuthorize("@ss.hasPermission('tjt:project:update')")
|
||||
public CommonResult<Boolean> updateProject(@Valid @RequestBody ProjectSaveReqVO updateReqVO) {
|
||||
projectService.updateProject(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除项目")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1")
|
||||
@PreAuthorize("@ss.hasPermission('tjt:project:delete')")
|
||||
public CommonResult<Boolean> deleteProject(@RequestParam("id") Long id) {
|
||||
projectService.deleteProject(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-list")
|
||||
@Operation(summary = "批量删除项目")
|
||||
@Parameter(name = "ids", description = "编号列表", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('tjt:project:delete')")
|
||||
public CommonResult<Boolean> deleteProjectList(@RequestParam("ids") List<Long> ids) {
|
||||
projectService.deleteProjectList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得项目分页")
|
||||
@PreAuthorize("@ss.hasPermission('tjt:project:query')")
|
||||
public CommonResult<PageResult<ProjectRespVO>> getProjectPage(@Valid ProjectPageReqVO pageReqVO) {
|
||||
PageResult<ProjectDO> pageResult = projectService.getProjectPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, ProjectRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得项目详情")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1")
|
||||
@PreAuthorize("@ss.hasPermission('tjt:project:query')")
|
||||
public CommonResult<ProjectRespVO> getProject(@RequestParam("id") Long id) {
|
||||
return success(BeanUtils.toBean(projectService.getProject(id), ProjectRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.controller.admin.project.vo;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.lyzsys.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 项目分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ProjectPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "工程名称,模糊匹配", example = "设计")
|
||||
private String projectName;
|
||||
|
||||
@Schema(description = "是否签订合同", example = "true")
|
||||
private Boolean contractSignedFlag;
|
||||
|
||||
@Schema(description = "项目开始年度", example = "2026")
|
||||
private Integer projectStartYear;
|
||||
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.controller.admin.project.vo;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 项目 Response VO")
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class ProjectRespVO {
|
||||
|
||||
private static final String FORMAT_YEAR_MONTH_DAY = "yyyy-MM-dd";
|
||||
|
||||
@Schema(description = "项目 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@ExcelProperty("项目ID")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "工程名称", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("工程名称")
|
||||
private String projectName;
|
||||
|
||||
@Schema(description = "是否签订合同", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("是否签订合同")
|
||||
private Boolean contractSignedFlag;
|
||||
|
||||
@Schema(description = "合同金额", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("合同金额")
|
||||
private BigDecimal contractAmount;
|
||||
|
||||
@Schema(description = "工程总面积", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("工程总面积")
|
||||
private BigDecimal totalConstructionArea;
|
||||
|
||||
@Schema(description = "建设单位")
|
||||
@ExcelProperty("建设单位")
|
||||
private String constructionUnitName;
|
||||
|
||||
@Schema(description = "联系人")
|
||||
@ExcelProperty("联系人")
|
||||
private String contactName;
|
||||
|
||||
@Schema(description = "联系方式")
|
||||
@ExcelProperty("联系方式")
|
||||
private String contactPhone;
|
||||
|
||||
@Schema(description = "合同签订日期")
|
||||
@ExcelProperty("合同签订日期")
|
||||
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||
private LocalDate contractSigningDate;
|
||||
|
||||
@Schema(description = "项目经理")
|
||||
@ExcelProperty("项目经理")
|
||||
private String projectManagerName;
|
||||
|
||||
@Schema(description = "工程负责人")
|
||||
@ExcelProperty("工程负责人")
|
||||
private String engineeringPrincipalName;
|
||||
|
||||
@Schema(description = "工程类型")
|
||||
@ExcelProperty("工程类型")
|
||||
private String projectType;
|
||||
|
||||
@Schema(description = "项目开始年度")
|
||||
@ExcelProperty("项目开始年度")
|
||||
private Integer projectStartYear;
|
||||
|
||||
@Schema(description = "最终结算金额")
|
||||
@ExcelProperty("最终结算金额")
|
||||
private BigDecimal finalSettlementAmount;
|
||||
|
||||
@Schema(description = "预计 K 值")
|
||||
@ExcelProperty("预计 K 值")
|
||||
private BigDecimal expectedKValue;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.controller.admin.project.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
|
||||
import static cn.iocoder.lyzsys.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
|
||||
|
||||
@Schema(description = "管理后台 - 项目新增/修改 Request VO")
|
||||
@Data
|
||||
public class ProjectSaveReqVO {
|
||||
|
||||
@Schema(description = "项目 ID", example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "工程名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "XX 设计项目")
|
||||
@NotBlank(message = "工程名称不能为空")
|
||||
@Size(max = 200, message = "工程名称长度不能超过 200 个字符")
|
||||
private String projectName;
|
||||
|
||||
@Schema(description = "是否签订合同", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
@NotNull(message = "是否签订合同不能为空")
|
||||
private Boolean contractSignedFlag;
|
||||
|
||||
@Schema(description = "合同金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000000")
|
||||
@NotNull(message = "合同金额不能为空")
|
||||
private BigDecimal contractAmount;
|
||||
|
||||
@Schema(description = "工程总面积", requiredMode = Schema.RequiredMode.REQUIRED, example = "30000")
|
||||
@NotNull(message = "工程总面积不能为空")
|
||||
private BigDecimal totalConstructionArea;
|
||||
|
||||
@Schema(description = "建设单位", example = "XX 建设单位")
|
||||
@Size(max = 200, message = "建设单位长度不能超过 200 个字符")
|
||||
private String constructionUnitName;
|
||||
|
||||
@Schema(description = "联系人", example = "张三")
|
||||
@Size(max = 64, message = "联系人长度不能超过 64 个字符")
|
||||
private String contactName;
|
||||
|
||||
@Schema(description = "联系方式", example = "13800000000")
|
||||
@Size(max = 32, message = "联系方式长度不能超过 32 个字符")
|
||||
private String contactPhone;
|
||||
|
||||
@Schema(description = "合同签订日期", example = "2026-04-14")
|
||||
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||
private LocalDate contractSigningDate;
|
||||
|
||||
@Schema(description = "项目经理", example = "李四")
|
||||
@Size(max = 64, message = "项目经理长度不能超过 64 个字符")
|
||||
private String projectManagerName;
|
||||
|
||||
@Schema(description = "工程负责人", example = "王五")
|
||||
@Size(max = 64, message = "工程负责人长度不能超过 64 个字符")
|
||||
private String engineeringPrincipalName;
|
||||
|
||||
@Schema(description = "工程类型", example = "住宅")
|
||||
@Size(max = 50, message = "工程类型长度不能超过 50 个字符")
|
||||
private String projectType;
|
||||
|
||||
@Schema(description = "项目开始年度", requiredMode = Schema.RequiredMode.REQUIRED, example = "2026")
|
||||
@NotNull(message = "项目开始年度不能为空")
|
||||
private Integer projectStartYear;
|
||||
|
||||
@Schema(description = "最终结算金额", example = "1200000")
|
||||
private BigDecimal finalSettlementAmount;
|
||||
|
||||
@Schema(description = "预计 K 值", example = "0.8500")
|
||||
private BigDecimal expectedKValue;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.controller.admin.specialtyrolesplit;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.specialtyrolesplit.vo.SpecialtyRoleSplitBatchSaveReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.specialtyrolesplit.vo.SpecialtyRoleSplitRespVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.service.specialtyrolesplit.SpecialtyRoleSplitService;
|
||||
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.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.lyzsys.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 特建投页面5角色比例")
|
||||
@RestController
|
||||
@RequestMapping("/tjt/specialty-role-split")
|
||||
@Validated
|
||||
public class SpecialtyRoleSplitController {
|
||||
|
||||
@Resource
|
||||
private SpecialtyRoleSplitService specialtyRoleSplitService;
|
||||
|
||||
@GetMapping("/list-by-planning")
|
||||
@Operation(summary = "根据合约规划获得页面5角色比例列表")
|
||||
@Parameter(name = "planningId", description = "合约规划 ID", required = true, example = "1")
|
||||
@PreAuthorize("@ss.hasPermission('tjt:specialty-role-split:query')")
|
||||
public CommonResult<List<SpecialtyRoleSplitRespVO>> getSpecialtyRoleSplitListByPlanningId(@RequestParam("planningId") Long planningId) {
|
||||
return success(specialtyRoleSplitService.getSpecialtyRoleSplitListByPlanningId(planningId));
|
||||
}
|
||||
|
||||
@PutMapping("/save-batch")
|
||||
@Operation(summary = "批量保存页面5角色比例")
|
||||
@PreAuthorize("@ss.hasPermission('tjt:specialty-role-split:update')")
|
||||
public CommonResult<Boolean> saveSpecialtyRoleSplitBatch(@Valid @RequestBody SpecialtyRoleSplitBatchSaveReqVO reqVO) {
|
||||
specialtyRoleSplitService.saveSpecialtyRoleSplitBatch(reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.controller.admin.specialtyrolesplit.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Schema(description = "管理后台 - 页面5角色人员 Response VO")
|
||||
@Data
|
||||
public class SpecialtyRolePersonRespVO {
|
||||
|
||||
@Schema(description = "人员名称")
|
||||
private String personName;
|
||||
|
||||
@Schema(description = "人员比例")
|
||||
private BigDecimal personRatio;
|
||||
|
||||
@Schema(description = "人员金额")
|
||||
private BigDecimal personAmount;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.controller.admin.specialtyrolesplit.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Schema(description = "管理后台 - 页面5角色人员保存 Item Request VO")
|
||||
@Data
|
||||
public class SpecialtyRolePersonSaveReqVO {
|
||||
|
||||
@Schema(description = "人员名称", example = "张三")
|
||||
private String personName;
|
||||
|
||||
@Schema(description = "人员比例", example = "0.1000")
|
||||
private BigDecimal personRatio;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.controller.admin.specialtyrolesplit.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 页面5角色比例批量保存 Request VO")
|
||||
@Data
|
||||
public class SpecialtyRoleSplitBatchSaveReqVO {
|
||||
|
||||
@Schema(description = "合约规划 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "合约规划 ID 不能为空")
|
||||
private Long planningId;
|
||||
|
||||
@Schema(description = "角色配置列表", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "角色配置列表不能为空")
|
||||
@Valid
|
||||
private List<SpecialtyRoleSplitSaveItemReqVO> items;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.controller.admin.specialtyrolesplit.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 页面5角色比例 Response VO")
|
||||
@Data
|
||||
public class SpecialtyRoleSplitRespVO {
|
||||
|
||||
@Schema(description = "角色比例 ID", example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "页面4拆分 ID", example = "1")
|
||||
private Long outputSplitId;
|
||||
|
||||
@Schema(description = "合同规划 ID", example = "1")
|
||||
private Long planningId;
|
||||
|
||||
@Schema(description = "项目名称")
|
||||
private String projectName;
|
||||
|
||||
@Schema(description = "规划内容")
|
||||
private String planningContent;
|
||||
|
||||
@Schema(description = "专业编码")
|
||||
private String specialtyCode;
|
||||
|
||||
@Schema(description = "专业名称")
|
||||
private String specialtyName;
|
||||
|
||||
@Schema(description = "专业金额")
|
||||
private BigDecimal specialtyAmount;
|
||||
|
||||
@Schema(description = "角色编码")
|
||||
private String roleCode;
|
||||
|
||||
@Schema(description = "角色名称")
|
||||
private String roleName;
|
||||
|
||||
@Schema(description = "角色比例")
|
||||
private BigDecimal roleRatio;
|
||||
|
||||
@Schema(description = "角色金额")
|
||||
private BigDecimal roleAmount;
|
||||
|
||||
@Schema(description = "人员配置列表")
|
||||
private List<SpecialtyRolePersonRespVO> persons;
|
||||
|
||||
@Schema(description = "排序号")
|
||||
private Integer sortNo;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.controller.admin.specialtyrolesplit.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 页面5角色比例保存 Item Request VO")
|
||||
@Data
|
||||
public class SpecialtyRoleSplitSaveItemReqVO {
|
||||
|
||||
@Schema(description = "专业编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "arch")
|
||||
@NotBlank(message = "专业编码不能为空")
|
||||
private String specialtyCode;
|
||||
|
||||
@Schema(description = "角色编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "director")
|
||||
@NotBlank(message = "角色编码不能为空")
|
||||
private String roleCode;
|
||||
|
||||
@Schema(description = "角色比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "0.1000")
|
||||
@NotNull(message = "角色比例不能为空")
|
||||
private BigDecimal roleRatio;
|
||||
|
||||
@Schema(description = "人员配置列表")
|
||||
@Valid
|
||||
private List<SpecialtyRolePersonSaveReqVO> persons;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.dal.dataobject.outputsplit;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.tenant.core.db.TenantBaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 页面 4 拆分比例 DO
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
@TableName("tjt_project_output_split")
|
||||
@KeySequence("tjt_project_output_split_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ProjectOutputSplitDO extends TenantBaseDO {
|
||||
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
private Long projectId;
|
||||
|
||||
private Long planningId;
|
||||
|
||||
private Integer year;
|
||||
|
||||
private BigDecimal projectManagerRatio;
|
||||
|
||||
private BigDecimal engineeringLeaderRatio;
|
||||
|
||||
private BigDecimal officeRatio;
|
||||
|
||||
private BigDecimal archRatio;
|
||||
|
||||
private BigDecimal decorRatio;
|
||||
|
||||
private BigDecimal structRatio;
|
||||
|
||||
private BigDecimal waterRatio;
|
||||
|
||||
private BigDecimal elecRatio;
|
||||
|
||||
private BigDecimal hvacRatio;
|
||||
|
||||
private BigDecimal digitalRatio;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.dal.dataobject.planning;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.tenant.core.db.TenantBaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 合约规划 DO
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
@TableName("tjt_project_planning")
|
||||
@KeySequence("tjt_project_planning_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ProjectPlanningDO extends TenantBaseDO {
|
||||
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
private Long projectId;
|
||||
|
||||
private String ownershipType;
|
||||
|
||||
private String calculationMethod;
|
||||
|
||||
private String planningContent;
|
||||
|
||||
private BigDecimal planningAmount;
|
||||
|
||||
private BigDecimal managementFeeRate;
|
||||
|
||||
private BigDecimal managementFee;
|
||||
|
||||
private String implementationTeam;
|
||||
|
||||
private Integer planningStartYear;
|
||||
|
||||
private BigDecimal planningArea;
|
||||
|
||||
private String designStage;
|
||||
|
||||
private BigDecimal currentDesignStageRatio;
|
||||
|
||||
private Boolean reviewOutsourceFlag;
|
||||
|
||||
private BigDecimal reviewOutsourceRatio;
|
||||
|
||||
private BigDecimal totalDistributionAmount;
|
||||
|
||||
private String progressRemark;
|
||||
|
||||
private Integer buildingOrUnitCount;
|
||||
|
||||
private BigDecimal drawingSetFactor;
|
||||
|
||||
private BigDecimal scaleFactor;
|
||||
|
||||
private BigDecimal modificationFactor;
|
||||
|
||||
private BigDecimal complexityFactor;
|
||||
|
||||
private BigDecimal internalGuidanceUnitPrice;
|
||||
|
||||
private String virtualCalculationMethod;
|
||||
|
||||
private BigDecimal workingDayCount;
|
||||
|
||||
private BigDecimal workingDayUnitPrice;
|
||||
|
||||
private BigDecimal guidanceUnitPrice;
|
||||
|
||||
private BigDecimal guidanceTotalPrice;
|
||||
|
||||
private BigDecimal virtualTotalPrice;
|
||||
|
||||
private BigDecimal calculationRatio;
|
||||
|
||||
private BigDecimal contractUnitPrice;
|
||||
|
||||
private BigDecimal totalAdjustmentFactor;
|
||||
|
||||
private BigDecimal assessmentArea;
|
||||
|
||||
private BigDecimal virtualOutputValue;
|
||||
|
||||
private BigDecimal assessmentOutputValue;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.dal.dataobject.planningquarter;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.tenant.core.db.TenantBaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 合约规划季度分配 DO
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
@TableName("tjt_project_planning_quarter")
|
||||
@KeySequence("tjt_project_planning_quarter_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ProjectPlanningQuarterDO extends TenantBaseDO {
|
||||
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
private Long planningId;
|
||||
|
||||
private Integer distributionYear;
|
||||
|
||||
private Integer quarterNo;
|
||||
|
||||
private BigDecimal distributionRatio;
|
||||
|
||||
private BigDecimal distributionAmount;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.dal.dataobject.project;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.tenant.core.db.TenantBaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* 项目 DO
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
@TableName("tjt_project")
|
||||
@KeySequence("tjt_project_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ProjectDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 主键 ID
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 工程名称
|
||||
*/
|
||||
private String projectName;
|
||||
/**
|
||||
* 是否签订合同
|
||||
*/
|
||||
private Boolean contractSignedFlag;
|
||||
/**
|
||||
* 合同金额
|
||||
*/
|
||||
private BigDecimal contractAmount;
|
||||
/**
|
||||
* 工程总面积
|
||||
*/
|
||||
private BigDecimal totalConstructionArea;
|
||||
/**
|
||||
* 建设单位
|
||||
*/
|
||||
private String constructionUnitName;
|
||||
/**
|
||||
* 联系人
|
||||
*/
|
||||
private String contactName;
|
||||
/**
|
||||
* 联系方式
|
||||
*/
|
||||
private String contactPhone;
|
||||
/**
|
||||
* 合同签订日期
|
||||
*/
|
||||
private LocalDate contractSigningDate;
|
||||
/**
|
||||
* 项目经理
|
||||
*/
|
||||
private String projectManagerName;
|
||||
/**
|
||||
* 工程负责人
|
||||
*/
|
||||
private String engineeringPrincipalName;
|
||||
/**
|
||||
* 工程类型
|
||||
*/
|
||||
private String projectType;
|
||||
/**
|
||||
* 项目开始年度
|
||||
*/
|
||||
private Integer projectStartYear;
|
||||
/**
|
||||
* 最终结算金额
|
||||
*/
|
||||
private BigDecimal finalSettlementAmount;
|
||||
/**
|
||||
* 预计 K 值
|
||||
*/
|
||||
private BigDecimal expectedKValue;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.dal.dataobject.specialtyrolesplit;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.tenant.core.db.TenantBaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 页面 5 角色比例 DO
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
@TableName("tjt_specialty_role_split")
|
||||
@KeySequence("tjt_specialty_role_split_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SpecialtyRoleSplitDO extends TenantBaseDO {
|
||||
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
private Long outputSplitId;
|
||||
|
||||
private String specialtyCode;
|
||||
|
||||
private String specialtyName;
|
||||
|
||||
private String roleCode;
|
||||
|
||||
private String roleName;
|
||||
|
||||
private BigDecimal roleRatio;
|
||||
|
||||
private String personNames;
|
||||
|
||||
private Integer sortNo;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.dal.mysql.outputsplit;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.lyzsys.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.outputsplit.ProjectOutputSplitDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 页面 4 拆分比例 Mapper
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
@Mapper
|
||||
public interface ProjectOutputSplitMapper extends BaseMapperX<ProjectOutputSplitDO> {
|
||||
|
||||
default ProjectOutputSplitDO selectByPlanningId(Long planningId) {
|
||||
return selectOne(new LambdaQueryWrapperX<ProjectOutputSplitDO>()
|
||||
.eq(ProjectOutputSplitDO::getPlanningId, planningId));
|
||||
}
|
||||
|
||||
default List<ProjectOutputSplitDO> selectListByPlanningIds(Collection<Long> planningIds) {
|
||||
return selectList(new LambdaQueryWrapperX<ProjectOutputSplitDO>()
|
||||
.inIfPresent(ProjectOutputSplitDO::getPlanningId, planningIds));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.dal.mysql.planning;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.lyzsys.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.lyzsys.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.planning.vo.ProjectPlanningPageReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planning.ProjectPlanningDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 合约规划 Mapper
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
@Mapper
|
||||
public interface ProjectPlanningMapper extends BaseMapperX<ProjectPlanningDO> {
|
||||
|
||||
default PageResult<ProjectPlanningDO> selectPage(ProjectPlanningPageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<ProjectPlanningDO>()
|
||||
.eqIfPresent(ProjectPlanningDO::getProjectId, reqVO.getProjectId())
|
||||
.eqIfPresent(ProjectPlanningDO::getOwnershipType, reqVO.getOwnershipType())
|
||||
.eqIfPresent(ProjectPlanningDO::getCalculationMethod, reqVO.getCalculationMethod())
|
||||
.likeIfPresent(ProjectPlanningDO::getPlanningContent, reqVO.getPlanningContent())
|
||||
.eqIfPresent(ProjectPlanningDO::getPlanningStartYear, reqVO.getPlanningStartYear())
|
||||
.betweenIfPresent(ProjectPlanningDO::getCreateTime, reqVO.getCreateTime())
|
||||
.orderByDesc(ProjectPlanningDO::getId));
|
||||
}
|
||||
|
||||
default List<ProjectPlanningDO> selectListByProjectId(Long projectId) {
|
||||
return selectList(new LambdaQueryWrapperX<ProjectPlanningDO>()
|
||||
.eq(ProjectPlanningDO::getProjectId, projectId)
|
||||
.orderByDesc(ProjectPlanningDO::getId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.dal.mysql.planningquarter;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.lyzsys.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planningquarter.ProjectPlanningQuarterDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 合约规划季度分配 Mapper
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
@Mapper
|
||||
public interface ProjectPlanningQuarterMapper extends BaseMapperX<ProjectPlanningQuarterDO> {
|
||||
|
||||
default ProjectPlanningQuarterDO selectByPlanningIdAndDistributionYearAndQuarter(Long planningId,
|
||||
Integer distributionYear,
|
||||
Integer quarterNo) {
|
||||
return selectOne(ProjectPlanningQuarterDO::getPlanningId, planningId,
|
||||
ProjectPlanningQuarterDO::getDistributionYear, distributionYear,
|
||||
ProjectPlanningQuarterDO::getQuarterNo, quarterNo);
|
||||
}
|
||||
|
||||
default List<ProjectPlanningQuarterDO> selectListByPlanningId(Long planningId) {
|
||||
return selectList(new LambdaQueryWrapperX<ProjectPlanningQuarterDO>()
|
||||
.eq(ProjectPlanningQuarterDO::getPlanningId, planningId)
|
||||
.orderByAsc(ProjectPlanningQuarterDO::getDistributionYear)
|
||||
.orderByAsc(ProjectPlanningQuarterDO::getQuarterNo)
|
||||
.orderByAsc(ProjectPlanningQuarterDO::getId));
|
||||
}
|
||||
|
||||
default List<ProjectPlanningQuarterDO> selectListByPlanningIds(Collection<Long> planningIds) {
|
||||
if (planningIds == null || planningIds.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return selectList(new LambdaQueryWrapperX<ProjectPlanningQuarterDO>()
|
||||
.in(ProjectPlanningQuarterDO::getPlanningId, planningIds)
|
||||
.orderByAsc(ProjectPlanningQuarterDO::getDistributionYear)
|
||||
.orderByAsc(ProjectPlanningQuarterDO::getQuarterNo)
|
||||
.orderByAsc(ProjectPlanningQuarterDO::getId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.dal.mysql.project;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.lyzsys.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.lyzsys.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.project.vo.ProjectPageReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.project.ProjectDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 项目 Mapper
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
@Mapper
|
||||
public interface ProjectMapper extends BaseMapperX<ProjectDO> {
|
||||
|
||||
default PageResult<ProjectDO> selectPage(ProjectPageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<ProjectDO>()
|
||||
.likeIfPresent(ProjectDO::getProjectName, reqVO.getProjectName())
|
||||
.eqIfPresent(ProjectDO::getContractSignedFlag, reqVO.getContractSignedFlag())
|
||||
.eqIfPresent(ProjectDO::getProjectStartYear, reqVO.getProjectStartYear())
|
||||
.betweenIfPresent(ProjectDO::getCreateTime, reqVO.getCreateTime())
|
||||
.orderByDesc(ProjectDO::getId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.dal.mysql.specialtyrolesplit;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.lyzsys.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.specialtyrolesplit.SpecialtyRoleSplitDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 页面 5 角色比例 Mapper
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
@Mapper
|
||||
public interface SpecialtyRoleSplitMapper extends BaseMapperX<SpecialtyRoleSplitDO> {
|
||||
|
||||
default List<SpecialtyRoleSplitDO> selectListByOutputSplitId(Long outputSplitId) {
|
||||
return selectList(new LambdaQueryWrapperX<SpecialtyRoleSplitDO>()
|
||||
.eq(SpecialtyRoleSplitDO::getOutputSplitId, outputSplitId)
|
||||
.orderByAsc(SpecialtyRoleSplitDO::getSortNo)
|
||||
.orderByAsc(SpecialtyRoleSplitDO::getId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.enums;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.common.exception.ErrorCode;
|
||||
|
||||
/**
|
||||
* 特建投模块错误码
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
public interface ErrorCodeConstants {
|
||||
|
||||
// ========== 项目管理 1-020-001-000 ==========
|
||||
ErrorCode PROJECT_NOT_EXISTS = new ErrorCode(1_020_001_000, "项目不存在");
|
||||
|
||||
// ========== 合约规划管理 1-020-002-000 ==========
|
||||
ErrorCode PROJECT_PLANNING_NOT_EXISTS = new ErrorCode(1_020_002_000, "合约规划不存在");
|
||||
ErrorCode PROJECT_PLANNING_PROJECT_NOT_EXISTS = new ErrorCode(1_020_002_001, "关联项目不存在");
|
||||
ErrorCode PROJECT_PLANNING_OWNERSHIP_TYPE_INVALID = new ErrorCode(1_020_002_002, "归属类型不正确");
|
||||
ErrorCode PROJECT_PLANNING_CALCULATION_METHOD_INVALID = new ErrorCode(1_020_002_003, "产值计算方式不正确");
|
||||
ErrorCode PROJECT_PLANNING_OWNERSHIP_TYPE_IMMUTABLE = new ErrorCode(1_020_002_004, "归属类型保存后不允许修改");
|
||||
ErrorCode PROJECT_PLANNING_CALCULATION_METHOD_IMMUTABLE = new ErrorCode(1_020_002_005, "产值计算方式保存后不允许修改");
|
||||
ErrorCode PROJECT_PLANNING_VIRTUAL_CALCULATION_METHOD_INVALID = new ErrorCode(1_020_002_006, "虚拟产值计算方式不正确");
|
||||
|
||||
// ========== 季度分配管理 1-020-003-000 ==========
|
||||
ErrorCode PROJECT_PLANNING_QUARTER_NOT_EXISTS = new ErrorCode(1_020_003_000, "季度分配明细不存在");
|
||||
ErrorCode PROJECT_PLANNING_QUARTER_DUPLICATE = new ErrorCode(1_020_003_001, "同一合约规划下该年度季度分配已存在");
|
||||
ErrorCode PROJECT_PLANNING_QUARTER_PLANNING_NOT_EXISTS = new ErrorCode(1_020_003_002, "关联合约规划不存在");
|
||||
|
||||
// ========== 页面 4 拆分管理 1-020-004-000 ==========
|
||||
ErrorCode PROJECT_OUTPUT_SPLIT_PLANNING_NOT_EXISTS = new ErrorCode(1_020_004_000, "关联合约规划不存在");
|
||||
ErrorCode PROJECT_OUTPUT_SPLIT_NOT_MAJOR = new ErrorCode(1_020_004_001, "仅专业所记录允许进行页面4拆分");
|
||||
ErrorCode PROJECT_OUTPUT_SPLIT_RATIO_INVALID = new ErrorCode(1_020_004_002, "页面4比例合计必须等于 100%");
|
||||
|
||||
// ========== 页面 5 角色拆分管理 1-020-005-000 ==========
|
||||
ErrorCode SPECIALTY_ROLE_SPLIT_OUTPUT_SPLIT_NOT_EXISTS = new ErrorCode(1_020_005_000, "页面4拆分记录不存在");
|
||||
ErrorCode SPECIALTY_ROLE_SPLIT_ROLE_RATIO_INVALID = new ErrorCode(1_020_005_001, "页面5五类角色比例合计必须等于 100%");
|
||||
ErrorCode SPECIALTY_ROLE_SPLIT_SPECIALTY_INVALID = new ErrorCode(1_020_005_002, "专业编码不正确");
|
||||
ErrorCode SPECIALTY_ROLE_SPLIT_ROLE_INVALID = new ErrorCode(1_020_005_003, "角色编码不正确");
|
||||
ErrorCode SPECIALTY_ROLE_SPLIT_PERSON_INVALID = new ErrorCode(1_020_005_004, "页面5人员名称和比例必须同时填写");
|
||||
ErrorCode SPECIALTY_ROLE_SPLIT_DESIGN_PERSON_REQUIRED = new ErrorCode(1_020_005_005, "页面5设计角色金额大于 0 时必须配置人员");
|
||||
ErrorCode SPECIALTY_ROLE_SPLIT_PERSON_RATIO_INVALID = new ErrorCode(1_020_005_007, "页面5同一角色下人员比例之和不能大于 100%");
|
||||
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 页面 4 / 页面 5 业务常量
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
public final class OutputSplitBizConstants {
|
||||
|
||||
public static final String OWNERSHIP_TYPE_MAJOR = "专业所";
|
||||
|
||||
public static final String SPECIALTY_ARCH = "arch";
|
||||
public static final String SPECIALTY_DECOR = "decor";
|
||||
public static final String SPECIALTY_STRUCT = "struct";
|
||||
public static final String SPECIALTY_WATER = "water";
|
||||
public static final String SPECIALTY_ELEC = "elec";
|
||||
public static final String SPECIALTY_HVAC = "hvac";
|
||||
public static final String SPECIALTY_DIGITAL = "digital";
|
||||
|
||||
public static final String ROLE_DIRECTOR = "director";
|
||||
public static final String ROLE_CHECK = "check";
|
||||
public static final String ROLE_REVIEW = "review";
|
||||
public static final String ROLE_APPROVE = "approve";
|
||||
public static final String ROLE_DESIGN = "design";
|
||||
|
||||
public static final List<SpecialtyItem> SPECIALTY_ITEMS = Arrays.asList(
|
||||
new SpecialtyItem(SPECIALTY_ARCH, "建筑", 1),
|
||||
new SpecialtyItem(SPECIALTY_DECOR, "装修", 2),
|
||||
new SpecialtyItem(SPECIALTY_STRUCT, "结构", 3),
|
||||
new SpecialtyItem(SPECIALTY_WATER, "水", 4),
|
||||
new SpecialtyItem(SPECIALTY_ELEC, "电气", 5),
|
||||
new SpecialtyItem(SPECIALTY_HVAC, "暖通", 6),
|
||||
new SpecialtyItem(SPECIALTY_DIGITAL, "数字化设计", 7)
|
||||
);
|
||||
|
||||
public static final List<RoleItem> ROLE_ITEMS = Arrays.asList(
|
||||
new RoleItem(ROLE_DIRECTOR, "专业负责人", 1),
|
||||
new RoleItem(ROLE_CHECK, "校对", 2),
|
||||
new RoleItem(ROLE_REVIEW, "审核", 3),
|
||||
new RoleItem(ROLE_APPROVE, "审定", 4),
|
||||
new RoleItem(ROLE_DESIGN, "设计", 5)
|
||||
);
|
||||
|
||||
private OutputSplitBizConstants() {
|
||||
}
|
||||
|
||||
public static boolean isMajorOwnershipType(String value) {
|
||||
return OWNERSHIP_TYPE_MAJOR.equals(value);
|
||||
}
|
||||
|
||||
public static boolean isValidSpecialtyCode(String code) {
|
||||
return SPECIALTY_ITEMS.stream().anyMatch(item -> item.getCode().equals(code));
|
||||
}
|
||||
|
||||
public static boolean isValidRoleCode(String code) {
|
||||
return ROLE_ITEMS.stream().anyMatch(item -> item.getCode().equals(code));
|
||||
}
|
||||
|
||||
public static String getSpecialtyName(String code) {
|
||||
return SPECIALTY_ITEMS.stream()
|
||||
.filter(item -> item.getCode().equals(code))
|
||||
.findFirst()
|
||||
.map(SpecialtyItem::getName)
|
||||
.orElse(code);
|
||||
}
|
||||
|
||||
public static String getRoleName(String code) {
|
||||
return ROLE_ITEMS.stream()
|
||||
.filter(item -> item.getCode().equals(code))
|
||||
.findFirst()
|
||||
.map(RoleItem::getName)
|
||||
.orElse(code);
|
||||
}
|
||||
|
||||
public static int getRoleSortNo(String code) {
|
||||
return ROLE_ITEMS.stream()
|
||||
.filter(item -> item.getCode().equals(code))
|
||||
.findFirst()
|
||||
.map(RoleItem::getSortNo)
|
||||
.orElse(0);
|
||||
}
|
||||
|
||||
public static int getSpecialtySortNo(String code) {
|
||||
return SPECIALTY_ITEMS.stream()
|
||||
.filter(item -> item.getCode().equals(code))
|
||||
.findFirst()
|
||||
.map(SpecialtyItem::getSortNo)
|
||||
.orElse(0);
|
||||
}
|
||||
|
||||
public static Map<String, String> buildSpecialtyMap() {
|
||||
Map<String, String> map = new LinkedHashMap<>();
|
||||
for (SpecialtyItem item : SPECIALTY_ITEMS) {
|
||||
map.put(item.getCode(), item.getName());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public static class SpecialtyItem {
|
||||
|
||||
private final String code;
|
||||
private final String name;
|
||||
private final Integer sortNo;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public static class RoleItem {
|
||||
|
||||
private final String code;
|
||||
private final String name;
|
||||
private final Integer sortNo;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.enums;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 合约规划业务类型常量
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
public final class ProjectPlanningBizTypeConstants {
|
||||
|
||||
public static final String OWNERSHIP_TYPE_MAJOR = "专业所";
|
||||
public static final String OWNERSHIP_TYPE_COMPREHENSIVE = "综合所";
|
||||
public static final String OWNERSHIP_TYPE_SUBCONTRACT = "专业分包";
|
||||
|
||||
public static final String CALCULATION_METHOD_GUIDANCE_PRICE = "指导价法";
|
||||
public static final String CALCULATION_METHOD_CONTRACT_PRICE = "合同价法";
|
||||
public static final String CALCULATION_METHOD_VIRTUAL_OUTPUT = "虚拟产值法";
|
||||
|
||||
public static final String VIRTUAL_CALCULATION_METHOD_GUIDANCE_PRICE = "指导单价法";
|
||||
public static final String VIRTUAL_CALCULATION_METHOD_VIRTUAL_TOTAL_PRICE = "虚拟总价法";
|
||||
public static final String VIRTUAL_CALCULATION_METHOD_WORKING_DAY = "工日法";
|
||||
|
||||
private static final Set<String> OWNERSHIP_TYPES = new HashSet<>(Arrays.asList(
|
||||
OWNERSHIP_TYPE_MAJOR,
|
||||
OWNERSHIP_TYPE_COMPREHENSIVE,
|
||||
OWNERSHIP_TYPE_SUBCONTRACT
|
||||
));
|
||||
|
||||
private static final Set<String> CALCULATION_METHODS = new HashSet<>(Arrays.asList(
|
||||
CALCULATION_METHOD_GUIDANCE_PRICE,
|
||||
CALCULATION_METHOD_CONTRACT_PRICE,
|
||||
CALCULATION_METHOD_VIRTUAL_OUTPUT
|
||||
));
|
||||
|
||||
private static final Set<String> VIRTUAL_CALCULATION_METHODS = new HashSet<>(Arrays.asList(
|
||||
VIRTUAL_CALCULATION_METHOD_GUIDANCE_PRICE,
|
||||
VIRTUAL_CALCULATION_METHOD_VIRTUAL_TOTAL_PRICE,
|
||||
VIRTUAL_CALCULATION_METHOD_WORKING_DAY
|
||||
));
|
||||
|
||||
private ProjectPlanningBizTypeConstants() {
|
||||
}
|
||||
|
||||
public static boolean isValidOwnershipType(String value) {
|
||||
return OWNERSHIP_TYPES.contains(value);
|
||||
}
|
||||
|
||||
public static boolean isValidCalculationMethod(String value) {
|
||||
return CALCULATION_METHODS.contains(value);
|
||||
}
|
||||
|
||||
public static boolean isValidVirtualCalculationMethod(String value) {
|
||||
return VIRTUAL_CALCULATION_METHODS.contains(value);
|
||||
}
|
||||
|
||||
public static boolean isMajor(String value) {
|
||||
return OWNERSHIP_TYPE_MAJOR.equals(value);
|
||||
}
|
||||
|
||||
public static boolean isComprehensive(String value) {
|
||||
return OWNERSHIP_TYPE_COMPREHENSIVE.equals(value);
|
||||
}
|
||||
|
||||
public static boolean isSubcontract(String value) {
|
||||
return OWNERSHIP_TYPE_SUBCONTRACT.equals(value);
|
||||
}
|
||||
|
||||
public static boolean isGuidancePrice(String value) {
|
||||
return CALCULATION_METHOD_GUIDANCE_PRICE.equals(value);
|
||||
}
|
||||
|
||||
public static boolean isContractPrice(String value) {
|
||||
return CALCULATION_METHOD_CONTRACT_PRICE.equals(value);
|
||||
}
|
||||
|
||||
public static boolean isVirtualOutput(String value) {
|
||||
return CALCULATION_METHOD_VIRTUAL_OUTPUT.equals(value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.service.outputsplit;
|
||||
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.outputsplit.vo.ProjectOutputSplitRespVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.outputsplit.vo.ProjectOutputSplitSaveReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.outputsplit.ProjectOutputSplitDO;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 页面4拆分比例 Service 接口
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
public interface ProjectOutputSplitService {
|
||||
|
||||
ProjectOutputSplitRespVO getProjectOutputSplit(Long planningId);
|
||||
|
||||
Long saveProjectOutputSplit(ProjectOutputSplitSaveReqVO reqVO);
|
||||
|
||||
ProjectOutputSplitDO getOrCreateProjectOutputSplit(Long planningId);
|
||||
|
||||
Map<Long, ProjectOutputSplitDO> getProjectOutputSplitMap(Collection<Long> planningIds);
|
||||
|
||||
BigDecimal getSpecialtyAmount(ProjectOutputSplitDO outputSplit, BigDecimal assessmentOutputValue, String specialtyCode);
|
||||
|
||||
void deleteByPlanningId(Long planningId);
|
||||
|
||||
void deleteByPlanningIds(Collection<Long> planningIds);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.service.outputsplit;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.outputsplit.vo.ProjectOutputSplitRespVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.outputsplit.vo.ProjectOutputSplitSaveReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.outputsplit.ProjectOutputSplitDO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planning.ProjectPlanningDO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.project.ProjectDO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.mysql.outputsplit.ProjectOutputSplitMapper;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.mysql.planning.ProjectPlanningMapper;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.mysql.project.ProjectMapper;
|
||||
import cn.iocoder.lyzsys.module.tjt.enums.OutputSplitBizConstants;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.lyzsys.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_NOT_EXISTS;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_OUTPUT_SPLIT_NOT_MAJOR;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_OUTPUT_SPLIT_PLANNING_NOT_EXISTS;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_OUTPUT_SPLIT_RATIO_INVALID;
|
||||
|
||||
/**
|
||||
* 页面4拆分比例 Service 实现类
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class ProjectOutputSplitServiceImpl implements ProjectOutputSplitService {
|
||||
|
||||
private static final int RATIO_SCALE = 4;
|
||||
private static final int AMOUNT_SCALE = 2;
|
||||
private static final BigDecimal ZERO_RATIO = BigDecimal.ZERO.setScale(RATIO_SCALE, RoundingMode.HALF_UP);
|
||||
private static final BigDecimal ONE_RATIO = BigDecimal.ONE.setScale(RATIO_SCALE, RoundingMode.HALF_UP);
|
||||
private static final BigDecimal ZERO_AMOUNT = BigDecimal.ZERO.setScale(AMOUNT_SCALE, RoundingMode.HALF_UP);
|
||||
|
||||
@Resource
|
||||
private ProjectOutputSplitMapper projectOutputSplitMapper;
|
||||
@Resource
|
||||
private ProjectPlanningMapper projectPlanningMapper;
|
||||
@Resource
|
||||
private ProjectMapper projectMapper;
|
||||
|
||||
@Override
|
||||
public ProjectOutputSplitRespVO getProjectOutputSplit(Long planningId) {
|
||||
ProjectPlanningDO planning = validateMajorPlanning(planningId);
|
||||
ProjectDO project = validateProjectExists(planning.getProjectId());
|
||||
ProjectOutputSplitDO outputSplit = projectOutputSplitMapper.selectByPlanningId(planningId);
|
||||
if (outputSplit == null) {
|
||||
outputSplit = buildDefaultOutputSplit(planning);
|
||||
}
|
||||
return buildRespVO(outputSplit, planning, project);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long saveProjectOutputSplit(ProjectOutputSplitSaveReqVO reqVO) {
|
||||
ProjectPlanningDO planning = validateMajorPlanning(reqVO.getPlanningId());
|
||||
validateOutputSplitRatios(reqVO);
|
||||
ProjectOutputSplitDO outputSplit = projectOutputSplitMapper.selectByPlanningId(reqVO.getPlanningId());
|
||||
if (outputSplit == null) {
|
||||
outputSplit = BeanUtils.toBean(reqVO, ProjectOutputSplitDO.class);
|
||||
outputSplit.setProjectId(planning.getProjectId());
|
||||
outputSplit.setYear(getPlanningYear(planning));
|
||||
normalizeRatios(outputSplit);
|
||||
projectOutputSplitMapper.insert(outputSplit);
|
||||
} else {
|
||||
ProjectOutputSplitDO updateObj = BeanUtils.toBean(reqVO, ProjectOutputSplitDO.class);
|
||||
updateObj.setId(outputSplit.getId());
|
||||
updateObj.setProjectId(planning.getProjectId());
|
||||
updateObj.setYear(getPlanningYear(planning));
|
||||
normalizeRatios(updateObj);
|
||||
projectOutputSplitMapper.updateById(updateObj);
|
||||
outputSplit = updateObj;
|
||||
}
|
||||
return outputSplit.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectOutputSplitDO getOrCreateProjectOutputSplit(Long planningId) {
|
||||
ProjectPlanningDO planning = validateMajorPlanning(planningId);
|
||||
ProjectOutputSplitDO outputSplit = projectOutputSplitMapper.selectByPlanningId(planningId);
|
||||
if (outputSplit != null) {
|
||||
return outputSplit;
|
||||
}
|
||||
ProjectOutputSplitDO createObj = buildDefaultOutputSplit(planning);
|
||||
projectOutputSplitMapper.insert(createObj);
|
||||
return createObj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, ProjectOutputSplitDO> getProjectOutputSplitMap(Collection<Long> planningIds) {
|
||||
if (planningIds == null || planningIds.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return projectOutputSplitMapper.selectListByPlanningIds(planningIds).stream()
|
||||
.collect(Collectors.toMap(ProjectOutputSplitDO::getPlanningId, item -> item, (a, b) -> b));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getSpecialtyAmount(ProjectOutputSplitDO outputSplit, BigDecimal assessmentOutputValue, String specialtyCode) {
|
||||
if (outputSplit == null) {
|
||||
return ZERO_AMOUNT;
|
||||
}
|
||||
BigDecimal officeAmount = multiplyAmount(amount(assessmentOutputValue), ratio(outputSplit.getOfficeRatio()));
|
||||
return multiplyAmount(officeAmount, getSpecialtyRatio(outputSplit, specialtyCode));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteByPlanningId(Long planningId) {
|
||||
ProjectOutputSplitDO outputSplit = projectOutputSplitMapper.selectByPlanningId(planningId);
|
||||
if (outputSplit != null) {
|
||||
projectOutputSplitMapper.deleteById(outputSplit.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteByPlanningIds(Collection<Long> planningIds) {
|
||||
if (planningIds == null || planningIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
projectOutputSplitMapper.delete(new cn.iocoder.lyzsys.framework.mybatis.core.query.LambdaQueryWrapperX<ProjectOutputSplitDO>()
|
||||
.in(ProjectOutputSplitDO::getPlanningId, planningIds));
|
||||
}
|
||||
|
||||
private ProjectOutputSplitRespVO buildRespVO(ProjectOutputSplitDO outputSplit, ProjectPlanningDO planning, ProjectDO project) {
|
||||
ProjectOutputSplitRespVO respVO = BeanUtils.toBean(outputSplit, ProjectOutputSplitRespVO.class);
|
||||
BigDecimal assessmentOutputValue = amount(planning.getAssessmentOutputValue());
|
||||
BigDecimal projectManagerAmount = multiplyAmount(assessmentOutputValue, outputSplit.getProjectManagerRatio());
|
||||
BigDecimal engineeringLeaderAmount = multiplyAmount(assessmentOutputValue, outputSplit.getEngineeringLeaderRatio());
|
||||
BigDecimal officeAmount = multiplyAmount(assessmentOutputValue, outputSplit.getOfficeRatio());
|
||||
|
||||
respVO.setProjectName(project.getProjectName());
|
||||
respVO.setPlanningContent(planning.getPlanningContent());
|
||||
respVO.setYear(getPlanningYear(planning));
|
||||
respVO.setAssessmentOutputValue(assessmentOutputValue);
|
||||
respVO.setProjectManagerName(project.getProjectManagerName());
|
||||
respVO.setEngineeringLeaderName(project.getEngineeringPrincipalName());
|
||||
respVO.setProjectManagerAmount(projectManagerAmount);
|
||||
respVO.setEngineeringLeaderAmount(engineeringLeaderAmount);
|
||||
respVO.setOfficeAmount(officeAmount);
|
||||
respVO.setArchAmount(multiplyAmount(officeAmount, outputSplit.getArchRatio()));
|
||||
respVO.setDecorAmount(multiplyAmount(officeAmount, outputSplit.getDecorRatio()));
|
||||
respVO.setStructAmount(multiplyAmount(officeAmount, outputSplit.getStructRatio()));
|
||||
respVO.setWaterAmount(multiplyAmount(officeAmount, outputSplit.getWaterRatio()));
|
||||
respVO.setElecAmount(multiplyAmount(officeAmount, outputSplit.getElecRatio()));
|
||||
respVO.setHvacAmount(multiplyAmount(officeAmount, outputSplit.getHvacRatio()));
|
||||
respVO.setDigitalAmount(multiplyAmount(officeAmount, outputSplit.getDigitalRatio()));
|
||||
return respVO;
|
||||
}
|
||||
|
||||
private ProjectPlanningDO validateMajorPlanning(Long planningId) {
|
||||
ProjectPlanningDO planning = projectPlanningMapper.selectById(planningId);
|
||||
if (planning == null) {
|
||||
throw exception(PROJECT_OUTPUT_SPLIT_PLANNING_NOT_EXISTS);
|
||||
}
|
||||
if (!OutputSplitBizConstants.isMajorOwnershipType(planning.getOwnershipType())) {
|
||||
throw exception(PROJECT_OUTPUT_SPLIT_NOT_MAJOR);
|
||||
}
|
||||
return planning;
|
||||
}
|
||||
|
||||
private ProjectDO validateProjectExists(Long projectId) {
|
||||
ProjectDO project = projectMapper.selectById(projectId);
|
||||
if (project == null) {
|
||||
throw exception(PROJECT_NOT_EXISTS);
|
||||
}
|
||||
return project;
|
||||
}
|
||||
|
||||
private ProjectOutputSplitDO buildDefaultOutputSplit(ProjectPlanningDO planning) {
|
||||
ProjectOutputSplitDO outputSplit = new ProjectOutputSplitDO();
|
||||
outputSplit.setProjectId(planning.getProjectId());
|
||||
outputSplit.setPlanningId(planning.getId());
|
||||
outputSplit.setYear(getPlanningYear(planning));
|
||||
outputSplit.setProjectManagerRatio(ZERO_RATIO);
|
||||
outputSplit.setEngineeringLeaderRatio(ZERO_RATIO);
|
||||
outputSplit.setOfficeRatio(ONE_RATIO);
|
||||
outputSplit.setArchRatio(ONE_RATIO);
|
||||
outputSplit.setDecorRatio(ZERO_RATIO);
|
||||
outputSplit.setStructRatio(ZERO_RATIO);
|
||||
outputSplit.setWaterRatio(ZERO_RATIO);
|
||||
outputSplit.setElecRatio(ZERO_RATIO);
|
||||
outputSplit.setHvacRatio(ZERO_RATIO);
|
||||
outputSplit.setDigitalRatio(ZERO_RATIO);
|
||||
return outputSplit;
|
||||
}
|
||||
|
||||
private Integer getPlanningYear(ProjectPlanningDO planning) {
|
||||
return planning.getPlanningStartYear() == null ? 0 : planning.getPlanningStartYear();
|
||||
}
|
||||
|
||||
private void validateOutputSplitRatios(ProjectOutputSplitSaveReqVO reqVO) {
|
||||
BigDecimal projectTotal = ratio(reqVO.getProjectManagerRatio())
|
||||
.add(ratio(reqVO.getEngineeringLeaderRatio()))
|
||||
.add(ratio(reqVO.getOfficeRatio()))
|
||||
.setScale(RATIO_SCALE, RoundingMode.HALF_UP);
|
||||
BigDecimal specialtyTotal = ratio(reqVO.getArchRatio())
|
||||
.add(ratio(reqVO.getDecorRatio()))
|
||||
.add(ratio(reqVO.getStructRatio()))
|
||||
.add(ratio(reqVO.getWaterRatio()))
|
||||
.add(ratio(reqVO.getElecRatio()))
|
||||
.add(ratio(reqVO.getHvacRatio()))
|
||||
.add(ratio(reqVO.getDigitalRatio()))
|
||||
.setScale(RATIO_SCALE, RoundingMode.HALF_UP);
|
||||
if (projectTotal.compareTo(ONE_RATIO) > 0 || specialtyTotal.compareTo(ONE_RATIO) != 0) {
|
||||
throw exception(PROJECT_OUTPUT_SPLIT_RATIO_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
private void normalizeRatios(ProjectOutputSplitDO outputSplit) {
|
||||
normalize(outputSplit::setProjectManagerRatio, outputSplit.getProjectManagerRatio());
|
||||
normalize(outputSplit::setEngineeringLeaderRatio, outputSplit.getEngineeringLeaderRatio());
|
||||
normalize(outputSplit::setOfficeRatio, outputSplit.getOfficeRatio());
|
||||
normalize(outputSplit::setArchRatio, outputSplit.getArchRatio());
|
||||
normalize(outputSplit::setDecorRatio, outputSplit.getDecorRatio());
|
||||
normalize(outputSplit::setStructRatio, outputSplit.getStructRatio());
|
||||
normalize(outputSplit::setWaterRatio, outputSplit.getWaterRatio());
|
||||
normalize(outputSplit::setElecRatio, outputSplit.getElecRatio());
|
||||
normalize(outputSplit::setHvacRatio, outputSplit.getHvacRatio());
|
||||
normalize(outputSplit::setDigitalRatio, outputSplit.getDigitalRatio());
|
||||
}
|
||||
|
||||
private void normalize(Consumer<BigDecimal> consumer, BigDecimal value) {
|
||||
consumer.accept(ratio(value));
|
||||
}
|
||||
|
||||
private BigDecimal getSpecialtyRatio(ProjectOutputSplitDO outputSplit, String specialtyCode) {
|
||||
switch (specialtyCode) {
|
||||
case OutputSplitBizConstants.SPECIALTY_ARCH:
|
||||
return ratio(outputSplit.getArchRatio());
|
||||
case OutputSplitBizConstants.SPECIALTY_DECOR:
|
||||
return ratio(outputSplit.getDecorRatio());
|
||||
case OutputSplitBizConstants.SPECIALTY_STRUCT:
|
||||
return ratio(outputSplit.getStructRatio());
|
||||
case OutputSplitBizConstants.SPECIALTY_WATER:
|
||||
return ratio(outputSplit.getWaterRatio());
|
||||
case OutputSplitBizConstants.SPECIALTY_ELEC:
|
||||
return ratio(outputSplit.getElecRatio());
|
||||
case OutputSplitBizConstants.SPECIALTY_HVAC:
|
||||
return ratio(outputSplit.getHvacRatio());
|
||||
case OutputSplitBizConstants.SPECIALTY_DIGITAL:
|
||||
return ratio(outputSplit.getDigitalRatio());
|
||||
default:
|
||||
return ZERO_RATIO;
|
||||
}
|
||||
}
|
||||
|
||||
private BigDecimal multiplyAmount(BigDecimal left, BigDecimal right) {
|
||||
return amount(left).multiply(ratio(right)).setScale(AMOUNT_SCALE, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private BigDecimal amount(BigDecimal value) {
|
||||
return value == null ? ZERO_AMOUNT : value.setScale(AMOUNT_SCALE, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private BigDecimal ratio(BigDecimal value) {
|
||||
return value == null ? ZERO_RATIO : value.setScale(RATIO_SCALE, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.service.planning;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.planning.vo.ProjectPlanningPageReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.planning.vo.ProjectPlanningSaveReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planning.ProjectPlanningDO;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 合约规划 Service 接口
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
public interface ProjectPlanningService {
|
||||
|
||||
Long createProjectPlanning(ProjectPlanningSaveReqVO createReqVO);
|
||||
|
||||
void updateProjectPlanning(ProjectPlanningSaveReqVO updateReqVO);
|
||||
|
||||
void deleteProjectPlanning(Long id);
|
||||
|
||||
void deleteProjectPlanningList(List<Long> ids);
|
||||
|
||||
PageResult<ProjectPlanningDO> getProjectPlanningPage(ProjectPlanningPageReqVO pageReqVO);
|
||||
|
||||
List<ProjectPlanningDO> getProjectPlanningListByProjectId(Long projectId);
|
||||
|
||||
ProjectPlanningDO getProjectPlanning(Long id);
|
||||
|
||||
Map<Long, BigDecimal> getAllocatedAmountMap(Collection<Long> planningIds);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,438 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.service.planning;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.lyzsys.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.lyzsys.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.planning.vo.ProjectPlanningPageReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.planning.vo.ProjectPlanningSaveReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.outputsplit.ProjectOutputSplitDO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planning.ProjectPlanningDO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planningquarter.ProjectPlanningQuarterDO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.project.ProjectDO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.mysql.planning.ProjectPlanningMapper;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.mysql.planningquarter.ProjectPlanningQuarterMapper;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.mysql.project.ProjectMapper;
|
||||
import cn.iocoder.lyzsys.module.tjt.service.outputsplit.ProjectOutputSplitService;
|
||||
import cn.iocoder.lyzsys.module.tjt.service.specialtyrolesplit.SpecialtyRoleSplitService;
|
||||
import cn.iocoder.lyzsys.module.tjt.enums.ProjectPlanningBizTypeConstants;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import static cn.iocoder.lyzsys.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_PLANNING_CALCULATION_METHOD_IMMUTABLE;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_PLANNING_CALCULATION_METHOD_INVALID;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_PLANNING_NOT_EXISTS;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_PLANNING_OWNERSHIP_TYPE_IMMUTABLE;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_PLANNING_OWNERSHIP_TYPE_INVALID;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_PLANNING_PROJECT_NOT_EXISTS;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_PLANNING_VIRTUAL_CALCULATION_METHOD_INVALID;
|
||||
|
||||
/**
|
||||
* 合约规划 Service 实现类
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class ProjectPlanningServiceImpl implements ProjectPlanningService {
|
||||
|
||||
private static final int AMOUNT_SCALE = 2;
|
||||
private static final int RATIO_SCALE = 4;
|
||||
private static final int FACTOR_SCALE = 2;
|
||||
|
||||
private static final BigDecimal ZERO_AMOUNT = BigDecimal.ZERO.setScale(AMOUNT_SCALE, RoundingMode.HALF_UP);
|
||||
private static final BigDecimal ZERO_RATIO = BigDecimal.ZERO.setScale(RATIO_SCALE, RoundingMode.HALF_UP);
|
||||
private static final BigDecimal ONE_RATIO = BigDecimal.ONE.setScale(RATIO_SCALE, RoundingMode.HALF_UP);
|
||||
private static final BigDecimal DEFAULT_COMPREHENSIVE_RATIO = new BigDecimal("0.0800");
|
||||
private static final BigDecimal DEFAULT_SUBCONTRACT_RATIO = new BigDecimal("0.0400");
|
||||
private static final BigDecimal DEFAULT_MAJOR_OUTSOURCE_RATIO = new BigDecimal("0.0600");
|
||||
private static final BigDecimal DEFAULT_COMMON_OUTSOURCE_RATIO = new BigDecimal("0.2500");
|
||||
private static final BigDecimal DEFAULT_WORKING_DAY_UNIT_PRICE = new BigDecimal("1000.00");
|
||||
private static final BigDecimal MIN_GUIDANCE_PRICE_RATIO = new BigDecimal("0.6000");
|
||||
|
||||
@Resource
|
||||
private ProjectPlanningMapper projectPlanningMapper;
|
||||
@Resource
|
||||
private ProjectMapper projectMapper;
|
||||
@Resource
|
||||
private ProjectPlanningQuarterMapper projectPlanningQuarterMapper;
|
||||
@Resource
|
||||
private ProjectOutputSplitService projectOutputSplitService;
|
||||
@Resource
|
||||
private SpecialtyRoleSplitService specialtyRoleSplitService;
|
||||
|
||||
@Override
|
||||
public Long createProjectPlanning(ProjectPlanningSaveReqVO createReqVO) {
|
||||
ProjectDO project = validateProjectExists(createReqVO.getProjectId());
|
||||
validateProjectPlanningForSave(createReqVO, null);
|
||||
ProjectPlanningDO planning = BeanUtils.toBean(createReqVO, ProjectPlanningDO.class);
|
||||
prepareProjectPlanning(planning, project);
|
||||
calculateProjectPlanning(planning);
|
||||
projectPlanningMapper.insert(planning);
|
||||
return planning.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProjectPlanning(ProjectPlanningSaveReqVO updateReqVO) {
|
||||
ProjectPlanningDO dbPlanning = validateProjectPlanningExists(updateReqVO.getId());
|
||||
ProjectDO project = validateProjectExists(updateReqVO.getProjectId());
|
||||
validateProjectPlanningForSave(updateReqVO, dbPlanning);
|
||||
ProjectPlanningDO updateObj = BeanUtils.toBean(updateReqVO, ProjectPlanningDO.class);
|
||||
prepareProjectPlanning(updateObj, project);
|
||||
calculateProjectPlanning(updateObj);
|
||||
projectPlanningMapper.updateById(updateObj);
|
||||
refreshQuarterDistributionAmounts(updateObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteProjectPlanning(Long id) {
|
||||
validateProjectPlanningExists(id);
|
||||
ProjectOutputSplitDO outputSplit = projectOutputSplitService.getProjectOutputSplitMap(Collections.singleton(id)).get(id);
|
||||
if (outputSplit != null) {
|
||||
specialtyRoleSplitService.deleteByOutputSplitId(outputSplit.getId());
|
||||
projectOutputSplitService.deleteByPlanningId(id);
|
||||
}
|
||||
projectPlanningQuarterMapper.delete(ProjectPlanningQuarterDO::getPlanningId, id);
|
||||
projectPlanningMapper.deleteById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteProjectPlanningList(List<Long> ids) {
|
||||
ids.forEach(this::validateProjectPlanningExists);
|
||||
Map<Long, ProjectOutputSplitDO> outputSplitMap = projectOutputSplitService.getProjectOutputSplitMap(ids);
|
||||
if (!outputSplitMap.isEmpty()) {
|
||||
specialtyRoleSplitService.deleteByOutputSplitIds(outputSplitMap.values().stream()
|
||||
.map(ProjectOutputSplitDO::getId)
|
||||
.collect(java.util.stream.Collectors.toList()));
|
||||
projectOutputSplitService.deleteByPlanningIds(ids);
|
||||
}
|
||||
projectPlanningQuarterMapper.deleteBatch(ProjectPlanningQuarterDO::getPlanningId, ids);
|
||||
projectPlanningMapper.deleteBatchIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<ProjectPlanningDO> getProjectPlanningPage(ProjectPlanningPageReqVO pageReqVO) {
|
||||
if (pageReqVO.getProjectId() != null) {
|
||||
validateProjectExists(pageReqVO.getProjectId());
|
||||
}
|
||||
return projectPlanningMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProjectPlanningDO> getProjectPlanningListByProjectId(Long projectId) {
|
||||
validateProjectExists(projectId);
|
||||
return projectPlanningMapper.selectListByProjectId(projectId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectPlanningDO getProjectPlanning(Long id) {
|
||||
return projectPlanningMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, BigDecimal> getAllocatedAmountMap(Collection<Long> planningIds) {
|
||||
if (planningIds == null || planningIds.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
List<ProjectPlanningQuarterDO> quarterList = projectPlanningQuarterMapper.selectListByPlanningIds(planningIds);
|
||||
Map<Long, BigDecimal> allocatedAmountMap = new HashMap<>();
|
||||
for (Long planningId : planningIds) {
|
||||
allocatedAmountMap.put(planningId, ZERO_RATIO);
|
||||
}
|
||||
for (ProjectPlanningQuarterDO quarter : quarterList) {
|
||||
allocatedAmountMap.merge(quarter.getPlanningId(), ratio(quarter.getDistributionRatio()), BigDecimal::add);
|
||||
}
|
||||
allocatedAmountMap.replaceAll((key, value) -> ratio(value));
|
||||
return allocatedAmountMap;
|
||||
}
|
||||
|
||||
private void validateProjectPlanningForSave(ProjectPlanningSaveReqVO reqVO, ProjectPlanningDO dbPlanning) {
|
||||
if (!ProjectPlanningBizTypeConstants.isValidOwnershipType(reqVO.getOwnershipType())) {
|
||||
throw exception(PROJECT_PLANNING_OWNERSHIP_TYPE_INVALID);
|
||||
}
|
||||
if (!ProjectPlanningBizTypeConstants.isValidCalculationMethod(reqVO.getCalculationMethod())) {
|
||||
throw exception(PROJECT_PLANNING_CALCULATION_METHOD_INVALID);
|
||||
}
|
||||
if (ProjectPlanningBizTypeConstants.isVirtualOutput(reqVO.getCalculationMethod())
|
||||
&& StrUtil.isNotBlank(reqVO.getVirtualCalculationMethod())
|
||||
&& !ProjectPlanningBizTypeConstants.isValidVirtualCalculationMethod(reqVO.getVirtualCalculationMethod())) {
|
||||
throw exception(PROJECT_PLANNING_VIRTUAL_CALCULATION_METHOD_INVALID);
|
||||
}
|
||||
if (dbPlanning == null) {
|
||||
return;
|
||||
}
|
||||
if (!Objects.equals(dbPlanning.getOwnershipType(), reqVO.getOwnershipType())) {
|
||||
throw exception(PROJECT_PLANNING_OWNERSHIP_TYPE_IMMUTABLE);
|
||||
}
|
||||
if (!Objects.equals(dbPlanning.getCalculationMethod(), reqVO.getCalculationMethod())) {
|
||||
throw exception(PROJECT_PLANNING_CALCULATION_METHOD_IMMUTABLE);
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareProjectPlanning(ProjectPlanningDO planning, ProjectDO project) {
|
||||
if (planning.getPlanningStartYear() == null) {
|
||||
planning.setPlanningStartYear(project.getProjectStartYear());
|
||||
}
|
||||
if (planning.getReviewOutsourceFlag() == null) {
|
||||
planning.setReviewOutsourceFlag(Boolean.FALSE);
|
||||
}
|
||||
planning.setPlanningAmount(amount(planning.getPlanningAmount()));
|
||||
planning.setManagementFeeRate(ratio(planning.getManagementFeeRate()));
|
||||
if (planning.getPlanningArea() == null) {
|
||||
planning.setPlanningArea(project.getTotalConstructionArea());
|
||||
}
|
||||
planning.setPlanningArea(amount(planning.getPlanningArea()));
|
||||
planning.setCurrentDesignStageRatio(ratio(planning.getCurrentDesignStageRatio()));
|
||||
planning.setTotalDistributionAmount(planning.getTotalDistributionAmount() == null
|
||||
? ONE_RATIO : ratio(planning.getTotalDistributionAmount()));
|
||||
|
||||
if (planning.getReviewOutsourceRatio() == null) {
|
||||
planning.setReviewOutsourceRatio(defaultReviewOutsourceRatio(planning.getOwnershipType(),
|
||||
Boolean.TRUE.equals(planning.getReviewOutsourceFlag())));
|
||||
} else {
|
||||
planning.setReviewOutsourceRatio(ratio(planning.getReviewOutsourceRatio()));
|
||||
}
|
||||
if ((ProjectPlanningBizTypeConstants.isComprehensive(planning.getOwnershipType())
|
||||
|| ProjectPlanningBizTypeConstants.isSubcontract(planning.getOwnershipType()))
|
||||
&& planning.getCalculationRatio() == null) {
|
||||
planning.setCalculationRatio(defaultCalculationRatio(planning.getOwnershipType()));
|
||||
} else if (planning.getCalculationRatio() != null) {
|
||||
planning.setCalculationRatio(ratio(planning.getCalculationRatio()));
|
||||
}
|
||||
|
||||
planning.setDrawingSetFactor(factorNullable(planning.getDrawingSetFactor()));
|
||||
planning.setScaleFactor(factorNullable(planning.getScaleFactor()));
|
||||
planning.setModificationFactor(factorNullable(planning.getModificationFactor()));
|
||||
planning.setComplexityFactor(ratioNullable(planning.getComplexityFactor()));
|
||||
planning.setInternalGuidanceUnitPrice(amountNullable(planning.getInternalGuidanceUnitPrice()));
|
||||
planning.setWorkingDayCount(amountNullable(planning.getWorkingDayCount()));
|
||||
planning.setWorkingDayUnitPrice(amountNullable(planning.getWorkingDayUnitPrice()));
|
||||
planning.setGuidanceUnitPrice(amountNullable(planning.getGuidanceUnitPrice()));
|
||||
planning.setGuidanceTotalPrice(amountNullable(planning.getGuidanceTotalPrice()));
|
||||
planning.setVirtualTotalPrice(amountNullable(planning.getVirtualTotalPrice()));
|
||||
|
||||
if (ProjectPlanningBizTypeConstants.VIRTUAL_CALCULATION_METHOD_WORKING_DAY.equals(planning.getVirtualCalculationMethod())
|
||||
&& planning.getWorkingDayUnitPrice() == null) {
|
||||
planning.setWorkingDayUnitPrice(DEFAULT_WORKING_DAY_UNIT_PRICE);
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateProjectPlanning(ProjectPlanningDO planning) {
|
||||
planning.setManagementFee(multiplyAmount(planning.getPlanningAmount(), planning.getManagementFeeRate()));
|
||||
planning.setContractUnitPrice(divideAmount(planning.getPlanningAmount(), planning.getPlanningArea()));
|
||||
planning.setTotalAdjustmentFactor(ZERO_RATIO);
|
||||
planning.setAssessmentArea(ZERO_AMOUNT);
|
||||
planning.setVirtualOutputValue(ZERO_AMOUNT);
|
||||
planning.setAssessmentOutputValue(ZERO_AMOUNT);
|
||||
|
||||
if (ProjectPlanningBizTypeConstants.isMajor(planning.getOwnershipType())) {
|
||||
calculateMajorPlanning(planning);
|
||||
return;
|
||||
}
|
||||
if (ProjectPlanningBizTypeConstants.isComprehensive(planning.getOwnershipType())
|
||||
|| ProjectPlanningBizTypeConstants.isSubcontract(planning.getOwnershipType())) {
|
||||
planning.setAssessmentOutputValue(multiplyAmount(
|
||||
planning.getPlanningAmount(),
|
||||
ratio(planning.getCalculationRatio()),
|
||||
planning.getCurrentDesignStageRatio(),
|
||||
oneMinus(planning.getReviewOutsourceRatio())));
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateMajorPlanning(ProjectPlanningDO planning) {
|
||||
if (ProjectPlanningBizTypeConstants.isGuidancePrice(planning.getCalculationMethod())) {
|
||||
BigDecimal totalAdjustmentFactor = calculateTotalAdjustmentFactor(planning);
|
||||
planning.setTotalAdjustmentFactor(totalAdjustmentFactor);
|
||||
planning.setAssessmentArea(multiplyAmount(planning.getPlanningArea(), totalAdjustmentFactor));
|
||||
BigDecimal applicableUnitPrice = calculateApplicableUnitPrice(
|
||||
planning.getContractUnitPrice(), planning.getInternalGuidanceUnitPrice());
|
||||
planning.setAssessmentOutputValue(multiplyAmount(
|
||||
applicableUnitPrice,
|
||||
planning.getAssessmentArea(),
|
||||
planning.getCurrentDesignStageRatio(),
|
||||
oneMinus(planning.getReviewOutsourceRatio())));
|
||||
return;
|
||||
}
|
||||
if (ProjectPlanningBizTypeConstants.isContractPrice(planning.getCalculationMethod())) {
|
||||
BigDecimal totalAdjustmentFactor = calculateTotalAdjustmentFactor(planning);
|
||||
planning.setTotalAdjustmentFactor(totalAdjustmentFactor);
|
||||
planning.setAssessmentArea(multiplyAmount(planning.getPlanningArea(), totalAdjustmentFactor));
|
||||
planning.setAssessmentOutputValue(multiplyAmount(
|
||||
planning.getPlanningAmount(),
|
||||
totalAdjustmentFactor,
|
||||
planning.getCurrentDesignStageRatio(),
|
||||
oneMinus(planning.getReviewOutsourceRatio())));
|
||||
return;
|
||||
}
|
||||
if (ProjectPlanningBizTypeConstants.isVirtualOutput(planning.getCalculationMethod())) {
|
||||
planning.setTotalAdjustmentFactor(ONE_RATIO);
|
||||
planning.setVirtualOutputValue(calculateVirtualOutputValue(planning));
|
||||
planning.setAssessmentOutputValue(multiplyAmount(
|
||||
planning.getVirtualOutputValue(),
|
||||
planning.getCurrentDesignStageRatio(),
|
||||
oneMinus(planning.getReviewOutsourceRatio())));
|
||||
}
|
||||
}
|
||||
|
||||
private BigDecimal calculateTotalAdjustmentFactor(ProjectPlanningDO planning) {
|
||||
return productRatio(
|
||||
defaultFactor(planning.getDrawingSetFactor()),
|
||||
defaultFactor(planning.getScaleFactor()),
|
||||
defaultFactor(planning.getModificationFactor()),
|
||||
defaultFactor(planning.getComplexityFactor()));
|
||||
}
|
||||
|
||||
private BigDecimal calculateApplicableUnitPrice(BigDecimal contractUnitPrice, BigDecimal internalGuidanceUnitPrice) {
|
||||
BigDecimal guidanceUnitPrice = amount(internalGuidanceUnitPrice);
|
||||
if (guidanceUnitPrice.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
return ZERO_AMOUNT;
|
||||
}
|
||||
BigDecimal unitPrice = amount(contractUnitPrice);
|
||||
BigDecimal minimumGuidancePrice = multiplyAmount(guidanceUnitPrice, MIN_GUIDANCE_PRICE_RATIO);
|
||||
if (unitPrice.compareTo(guidanceUnitPrice) > 0) {
|
||||
return guidanceUnitPrice;
|
||||
}
|
||||
if (unitPrice.compareTo(minimumGuidancePrice) >= 0) {
|
||||
return unitPrice;
|
||||
}
|
||||
return minimumGuidancePrice;
|
||||
}
|
||||
|
||||
private BigDecimal calculateVirtualOutputValue(ProjectPlanningDO planning) {
|
||||
if (ProjectPlanningBizTypeConstants.VIRTUAL_CALCULATION_METHOD_WORKING_DAY.equals(planning.getVirtualCalculationMethod())) {
|
||||
return multiplyAmount(planning.getWorkingDayCount(), planning.getWorkingDayUnitPrice());
|
||||
}
|
||||
if (ProjectPlanningBizTypeConstants.VIRTUAL_CALCULATION_METHOD_GUIDANCE_PRICE.equals(planning.getVirtualCalculationMethod())) {
|
||||
if (isPositive(planning.getGuidanceTotalPrice())) {
|
||||
return amount(planning.getGuidanceTotalPrice());
|
||||
}
|
||||
return multiplyAmount(planning.getGuidanceUnitPrice(), planning.getPlanningArea());
|
||||
}
|
||||
if (ProjectPlanningBizTypeConstants.VIRTUAL_CALCULATION_METHOD_VIRTUAL_TOTAL_PRICE.equals(planning.getVirtualCalculationMethod())) {
|
||||
return amount(planning.getVirtualTotalPrice());
|
||||
}
|
||||
return ZERO_AMOUNT;
|
||||
}
|
||||
|
||||
private BigDecimal defaultReviewOutsourceRatio(String ownershipType, boolean outsourceFlag) {
|
||||
if (!outsourceFlag) {
|
||||
return ZERO_RATIO;
|
||||
}
|
||||
if (ProjectPlanningBizTypeConstants.isMajor(ownershipType)) {
|
||||
return DEFAULT_MAJOR_OUTSOURCE_RATIO;
|
||||
}
|
||||
return DEFAULT_COMMON_OUTSOURCE_RATIO;
|
||||
}
|
||||
|
||||
private BigDecimal defaultCalculationRatio(String ownershipType) {
|
||||
if (ProjectPlanningBizTypeConstants.isComprehensive(ownershipType)) {
|
||||
return DEFAULT_COMPREHENSIVE_RATIO;
|
||||
}
|
||||
if (ProjectPlanningBizTypeConstants.isSubcontract(ownershipType)) {
|
||||
return DEFAULT_SUBCONTRACT_RATIO;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private ProjectDO validateProjectExists(Long projectId) {
|
||||
ProjectDO project = projectMapper.selectById(projectId);
|
||||
if (project == null) {
|
||||
throw exception(PROJECT_PLANNING_PROJECT_NOT_EXISTS);
|
||||
}
|
||||
return project;
|
||||
}
|
||||
|
||||
private ProjectPlanningDO validateProjectPlanningExists(Long id) {
|
||||
ProjectPlanningDO planning = projectPlanningMapper.selectById(id);
|
||||
if (planning == null) {
|
||||
throw exception(PROJECT_PLANNING_NOT_EXISTS);
|
||||
}
|
||||
return planning;
|
||||
}
|
||||
|
||||
private BigDecimal multiplyAmount(BigDecimal... values) {
|
||||
BigDecimal result = BigDecimal.ONE;
|
||||
for (BigDecimal value : values) {
|
||||
result = result.multiply(value == null ? BigDecimal.ZERO : value);
|
||||
}
|
||||
return result.setScale(AMOUNT_SCALE, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private BigDecimal productRatio(BigDecimal... values) {
|
||||
BigDecimal result = BigDecimal.ONE;
|
||||
for (BigDecimal value : values) {
|
||||
result = result.multiply(value == null ? BigDecimal.ONE : value);
|
||||
}
|
||||
return result.setScale(RATIO_SCALE, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private BigDecimal divideAmount(BigDecimal dividend, BigDecimal divisor) {
|
||||
if (dividend == null || divisor == null || divisor.compareTo(BigDecimal.ZERO) == 0) {
|
||||
return ZERO_AMOUNT;
|
||||
}
|
||||
return dividend.divide(divisor, AMOUNT_SCALE, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private BigDecimal oneMinus(BigDecimal value) {
|
||||
return BigDecimal.ONE.subtract(ratio(value)).setScale(RATIO_SCALE, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private BigDecimal defaultFactor(BigDecimal value) {
|
||||
return value == null ? ONE_RATIO : ratio(value);
|
||||
}
|
||||
|
||||
private BigDecimal amount(BigDecimal value) {
|
||||
return value == null ? ZERO_AMOUNT : value.setScale(AMOUNT_SCALE, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private BigDecimal amountNullable(BigDecimal value) {
|
||||
return value == null ? null : amount(value);
|
||||
}
|
||||
|
||||
private BigDecimal factor(BigDecimal value) {
|
||||
return value == null ? BigDecimal.ZERO.setScale(FACTOR_SCALE, RoundingMode.HALF_UP)
|
||||
: value.setScale(FACTOR_SCALE, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private BigDecimal factorNullable(BigDecimal value) {
|
||||
return value == null ? null : factor(value);
|
||||
}
|
||||
|
||||
private BigDecimal ratio(BigDecimal value) {
|
||||
return value == null ? ZERO_RATIO : value.setScale(RATIO_SCALE, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private BigDecimal ratioNullable(BigDecimal value) {
|
||||
return value == null ? null : ratio(value);
|
||||
}
|
||||
|
||||
private boolean isPositive(BigDecimal value) {
|
||||
return value != null && value.compareTo(BigDecimal.ZERO) > 0;
|
||||
}
|
||||
|
||||
private void refreshQuarterDistributionAmounts(ProjectPlanningDO planning) {
|
||||
List<ProjectPlanningQuarterDO> quarterList = projectPlanningQuarterMapper.selectListByPlanningId(planning.getId());
|
||||
for (ProjectPlanningQuarterDO quarter : quarterList) {
|
||||
quarter.setDistributionAmount(calculateQuarterDistributionAmount(planning, quarter.getDistributionRatio()));
|
||||
projectPlanningQuarterMapper.updateById(quarter);
|
||||
}
|
||||
}
|
||||
|
||||
private BigDecimal calculateQuarterDistributionAmount(ProjectPlanningDO planning, BigDecimal distributionRatio) {
|
||||
return multiplyAmount(
|
||||
planning.getAssessmentOutputValue(),
|
||||
planning.getTotalDistributionAmount(),
|
||||
ratio(distributionRatio));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.service.planningquarter;
|
||||
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.planningquarter.vo.ProjectPlanningQuarterSaveReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planningquarter.ProjectPlanningQuarterDO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 季度分配 Service 接口
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
public interface ProjectPlanningQuarterService {
|
||||
|
||||
Long createProjectPlanningQuarter(ProjectPlanningQuarterSaveReqVO createReqVO);
|
||||
|
||||
void updateProjectPlanningQuarter(ProjectPlanningQuarterSaveReqVO updateReqVO);
|
||||
|
||||
void deleteProjectPlanningQuarter(Long id);
|
||||
|
||||
void deleteProjectPlanningQuarterList(List<Long> ids);
|
||||
|
||||
ProjectPlanningQuarterDO getProjectPlanningQuarter(Long id);
|
||||
|
||||
List<ProjectPlanningQuarterDO> getProjectPlanningQuarterListByPlanningId(Long planningId);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.service.planningquarter;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.planningquarter.vo.ProjectPlanningQuarterSaveReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planning.ProjectPlanningDO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planningquarter.ProjectPlanningQuarterDO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.mysql.planning.ProjectPlanningMapper;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.mysql.planningquarter.ProjectPlanningQuarterMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.lyzsys.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_PLANNING_QUARTER_DUPLICATE;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_PLANNING_QUARTER_NOT_EXISTS;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_PLANNING_QUARTER_PLANNING_NOT_EXISTS;
|
||||
|
||||
/**
|
||||
* 季度分配 Service 实现类
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class ProjectPlanningQuarterServiceImpl implements ProjectPlanningQuarterService {
|
||||
|
||||
private static final BigDecimal ZERO_AMOUNT = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
|
||||
private static final BigDecimal ZERO_RATIO = BigDecimal.ZERO.setScale(4, RoundingMode.HALF_UP);
|
||||
|
||||
@Resource
|
||||
private ProjectPlanningQuarterMapper projectPlanningQuarterMapper;
|
||||
@Resource
|
||||
private ProjectPlanningMapper projectPlanningMapper;
|
||||
|
||||
@Override
|
||||
public Long createProjectPlanningQuarter(ProjectPlanningQuarterSaveReqVO createReqVO) {
|
||||
ProjectPlanningDO planning = validatePlanningExists(createReqVO.getPlanningId());
|
||||
if (isZeroQuarter(createReqVO)) {
|
||||
return null;
|
||||
}
|
||||
validateQuarterUnique(null, createReqVO.getPlanningId(),
|
||||
createReqVO.getDistributionYear(), createReqVO.getQuarterNo());
|
||||
ProjectPlanningQuarterDO quarter = BeanUtils.toBean(createReqVO, ProjectPlanningQuarterDO.class);
|
||||
prepareQuarter(quarter, planning);
|
||||
projectPlanningQuarterMapper.insert(quarter);
|
||||
return quarter.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProjectPlanningQuarter(ProjectPlanningQuarterSaveReqVO updateReqVO) {
|
||||
ProjectPlanningQuarterDO dbQuarter = validateQuarterExists(updateReqVO.getId());
|
||||
ProjectPlanningDO planning = validatePlanningExists(updateReqVO.getPlanningId());
|
||||
if (isZeroQuarter(updateReqVO)) {
|
||||
projectPlanningQuarterMapper.deleteById(dbQuarter.getId());
|
||||
return;
|
||||
}
|
||||
validateQuarterUnique(updateReqVO.getId(), updateReqVO.getPlanningId(),
|
||||
updateReqVO.getDistributionYear(), updateReqVO.getQuarterNo());
|
||||
ProjectPlanningQuarterDO updateObj = BeanUtils.toBean(updateReqVO, ProjectPlanningQuarterDO.class);
|
||||
prepareQuarter(updateObj, planning);
|
||||
projectPlanningQuarterMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteProjectPlanningQuarter(Long id) {
|
||||
validateQuarterExists(id);
|
||||
projectPlanningQuarterMapper.deleteById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteProjectPlanningQuarterList(List<Long> ids) {
|
||||
ids.forEach(this::validateQuarterExists);
|
||||
projectPlanningQuarterMapper.deleteBatchIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectPlanningQuarterDO getProjectPlanningQuarter(Long id) {
|
||||
return projectPlanningQuarterMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProjectPlanningQuarterDO> getProjectPlanningQuarterListByPlanningId(Long planningId) {
|
||||
validatePlanningExists(planningId);
|
||||
return projectPlanningQuarterMapper.selectListByPlanningId(planningId);
|
||||
}
|
||||
|
||||
private void validateQuarterUnique(Long id, Long planningId, Integer distributionYear, Integer quarterNo) {
|
||||
ProjectPlanningQuarterDO quarter = projectPlanningQuarterMapper.selectByPlanningIdAndDistributionYearAndQuarter(
|
||||
planningId, distributionYear, quarterNo);
|
||||
if (quarter == null) {
|
||||
return;
|
||||
}
|
||||
if (id == null || !quarter.getId().equals(id)) {
|
||||
throw exception(PROJECT_PLANNING_QUARTER_DUPLICATE);
|
||||
}
|
||||
}
|
||||
|
||||
private ProjectPlanningDO validatePlanningExists(Long planningId) {
|
||||
ProjectPlanningDO planning = projectPlanningMapper.selectById(planningId);
|
||||
if (planning == null) {
|
||||
throw exception(PROJECT_PLANNING_QUARTER_PLANNING_NOT_EXISTS);
|
||||
}
|
||||
return planning;
|
||||
}
|
||||
|
||||
private ProjectPlanningQuarterDO validateQuarterExists(Long id) {
|
||||
ProjectPlanningQuarterDO quarter = projectPlanningQuarterMapper.selectById(id);
|
||||
if (quarter == null) {
|
||||
throw exception(PROJECT_PLANNING_QUARTER_NOT_EXISTS);
|
||||
}
|
||||
return quarter;
|
||||
}
|
||||
|
||||
private boolean isZeroQuarter(ProjectPlanningQuarterSaveReqVO reqVO) {
|
||||
return ratio(reqVO.getDistributionRatio()).compareTo(BigDecimal.ZERO) == 0;
|
||||
}
|
||||
|
||||
private void prepareQuarter(ProjectPlanningQuarterDO quarter, ProjectPlanningDO planning) {
|
||||
quarter.setDistributionRatio(ratio(quarter.getDistributionRatio()));
|
||||
quarter.setDistributionAmount(multiplyAmount(
|
||||
planning.getAssessmentOutputValue(),
|
||||
planning.getTotalDistributionAmount(),
|
||||
quarter.getDistributionRatio()));
|
||||
}
|
||||
|
||||
private BigDecimal amount(BigDecimal value) {
|
||||
return value == null ? ZERO_AMOUNT : value.setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private BigDecimal ratio(BigDecimal value) {
|
||||
return value == null ? ZERO_RATIO : value.setScale(4, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private BigDecimal multiplyAmount(BigDecimal... values) {
|
||||
BigDecimal result = BigDecimal.ONE;
|
||||
for (BigDecimal value : values) {
|
||||
result = result.multiply(value == null ? BigDecimal.ZERO : value);
|
||||
}
|
||||
return result.setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.service.profit;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.profit.vo.ProjectProfitPageReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.profit.vo.ProjectProfitRespVO;
|
||||
|
||||
/**
|
||||
* 项目盈亏 Service 接口
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
public interface ProjectProfitService {
|
||||
|
||||
ProjectProfitRespVO getProjectProfit(Long projectId);
|
||||
|
||||
PageResult<ProjectProfitRespVO> getProjectProfitPage(ProjectProfitPageReqVO pageReqVO);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.service.profit;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.lyzsys.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.lyzsys.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.profit.vo.ProjectProfitPageReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.profit.vo.ProjectProfitRespVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planning.ProjectPlanningDO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.project.ProjectDO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.mysql.planning.ProjectPlanningMapper;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.mysql.project.ProjectMapper;
|
||||
import cn.iocoder.lyzsys.module.tjt.enums.ProjectPlanningBizTypeConstants;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.lyzsys.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_NOT_EXISTS;
|
||||
|
||||
/**
|
||||
* 项目盈亏 Service 实现类
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class ProjectProfitServiceImpl implements ProjectProfitService {
|
||||
|
||||
private static final BigDecimal ZERO_AMOUNT = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
|
||||
private static final BigDecimal ZERO_RATIO = BigDecimal.ZERO.setScale(4, RoundingMode.HALF_UP);
|
||||
|
||||
@Resource
|
||||
private ProjectMapper projectMapper;
|
||||
@Resource
|
||||
private ProjectPlanningMapper projectPlanningMapper;
|
||||
|
||||
@Override
|
||||
public ProjectProfitRespVO getProjectProfit(Long projectId) {
|
||||
ProjectDO project = validateProjectExists(projectId);
|
||||
List<ProjectPlanningDO> planningList = projectPlanningMapper.selectList(ProjectPlanningDO::getProjectId,
|
||||
Collections.singleton(projectId));
|
||||
return buildProjectProfit(project, planningList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<ProjectProfitRespVO> getProjectProfitPage(ProjectProfitPageReqVO pageReqVO) {
|
||||
PageResult<ProjectDO> pageResult = projectMapper.selectPage(pageReqVO, new LambdaQueryWrapperX<ProjectDO>()
|
||||
.likeIfPresent(ProjectDO::getProjectName, pageReqVO.getProjectName())
|
||||
.eqIfPresent(ProjectDO::getContractSignedFlag, pageReqVO.getContractSignedFlag())
|
||||
.eqIfPresent(ProjectDO::getProjectStartYear, pageReqVO.getProjectStartYear())
|
||||
.betweenIfPresent(ProjectDO::getCreateTime, pageReqVO.getCreateTime())
|
||||
.orderByDesc(ProjectDO::getId));
|
||||
if (pageResult.getList().isEmpty()) {
|
||||
return new PageResult<>(Collections.emptyList(), pageResult.getTotal());
|
||||
}
|
||||
Map<Long, List<ProjectPlanningDO>> planningMap = CollectionUtils.convertMultiMap(
|
||||
projectPlanningMapper.selectList(ProjectPlanningDO::getProjectId,
|
||||
CollectionUtils.convertSet(pageResult.getList(), ProjectDO::getId)),
|
||||
ProjectPlanningDO::getProjectId);
|
||||
List<ProjectProfitRespVO> list = CollectionUtils.convertList(pageResult.getList(),
|
||||
project -> buildProjectProfit(project, planningMap.get(project.getId())));
|
||||
return new PageResult<>(list, pageResult.getTotal());
|
||||
}
|
||||
|
||||
private ProjectProfitRespVO buildProjectProfit(ProjectDO project, List<ProjectPlanningDO> planningList) {
|
||||
List<ProjectPlanningDO> safePlanningList = planningList == null ? Collections.emptyList() : planningList;
|
||||
BigDecimal comprehensivePlanningAmount = ZERO_AMOUNT;
|
||||
BigDecimal subcontractPlanningAmount = ZERO_AMOUNT;
|
||||
BigDecimal majorOutputValue = ZERO_AMOUNT;
|
||||
for (ProjectPlanningDO planning : safePlanningList) {
|
||||
if (ProjectPlanningBizTypeConstants.isComprehensive(planning.getOwnershipType())) {
|
||||
comprehensivePlanningAmount = comprehensivePlanningAmount.add(amount(planning.getPlanningAmount()));
|
||||
continue;
|
||||
}
|
||||
if (ProjectPlanningBizTypeConstants.isSubcontract(planning.getOwnershipType())) {
|
||||
subcontractPlanningAmount = subcontractPlanningAmount.add(amount(planning.getPlanningAmount()));
|
||||
continue;
|
||||
}
|
||||
if (ProjectPlanningBizTypeConstants.isMajor(planning.getOwnershipType())) {
|
||||
majorOutputValue = majorOutputValue.add(amount(planning.getAssessmentOutputValue()));
|
||||
}
|
||||
}
|
||||
BigDecimal expectedKValue = ratio(project.getExpectedKValue());
|
||||
BigDecimal majorExpectedPerformance = majorOutputValue.multiply(expectedKValue).setScale(2, RoundingMode.HALF_UP);
|
||||
BigDecimal finalSettlementAmount = amount(project.getFinalSettlementAmount());
|
||||
BigDecimal profitLossValue = finalSettlementAmount
|
||||
.subtract(comprehensivePlanningAmount)
|
||||
.subtract(subcontractPlanningAmount)
|
||||
.subtract(majorExpectedPerformance)
|
||||
.setScale(2, RoundingMode.HALF_UP);
|
||||
BigDecimal profitLossRate = finalSettlementAmount.compareTo(BigDecimal.ZERO) == 0
|
||||
? ZERO_RATIO
|
||||
: profitLossValue.divide(finalSettlementAmount, 4, RoundingMode.HALF_UP);
|
||||
|
||||
ProjectProfitRespVO respVO = new ProjectProfitRespVO();
|
||||
respVO.setProjectId(project.getId());
|
||||
respVO.setProjectName(project.getProjectName());
|
||||
respVO.setContractSignedFlag(project.getContractSignedFlag());
|
||||
respVO.setContractAmount(amount(project.getContractAmount()));
|
||||
respVO.setFinalSettlementAmount(finalSettlementAmount);
|
||||
respVO.setComprehensivePlanningAmount(comprehensivePlanningAmount.setScale(2, RoundingMode.HALF_UP));
|
||||
respVO.setSubcontractPlanningAmount(subcontractPlanningAmount.setScale(2, RoundingMode.HALF_UP));
|
||||
respVO.setMajorOutputValue(majorOutputValue.setScale(2, RoundingMode.HALF_UP));
|
||||
respVO.setExpectedKValue(expectedKValue);
|
||||
respVO.setMajorExpectedPerformance(majorExpectedPerformance);
|
||||
respVO.setProfitLossValue(profitLossValue);
|
||||
respVO.setProfitLossRate(profitLossRate);
|
||||
respVO.setProjectStartYear(project.getProjectStartYear());
|
||||
respVO.setCreateTime(project.getCreateTime());
|
||||
return respVO;
|
||||
}
|
||||
|
||||
private ProjectDO validateProjectExists(Long projectId) {
|
||||
ProjectDO project = projectMapper.selectById(projectId);
|
||||
if (project == null) {
|
||||
throw exception(PROJECT_NOT_EXISTS);
|
||||
}
|
||||
return project;
|
||||
}
|
||||
|
||||
private BigDecimal amount(BigDecimal value) {
|
||||
return value == null ? ZERO_AMOUNT : value.setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private BigDecimal ratio(BigDecimal value) {
|
||||
return value == null ? ZERO_RATIO : value.setScale(4, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.service.project;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.project.vo.ProjectPageReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.project.vo.ProjectSaveReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.project.ProjectDO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 项目 Service 接口
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
public interface ProjectService {
|
||||
|
||||
Long createProject(ProjectSaveReqVO createReqVO);
|
||||
|
||||
void updateProject(ProjectSaveReqVO updateReqVO);
|
||||
|
||||
void deleteProject(Long id);
|
||||
|
||||
void deleteProjectList(List<Long> ids);
|
||||
|
||||
PageResult<ProjectDO> getProjectPage(ProjectPageReqVO pageReqVO);
|
||||
|
||||
ProjectDO getProject(Long id);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.service.project;
|
||||
|
||||
import cn.iocoder.lyzsys.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.lyzsys.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.project.vo.ProjectPageReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.project.vo.ProjectSaveReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.project.ProjectDO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.mysql.project.ProjectMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.lyzsys.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_NOT_EXISTS;
|
||||
|
||||
/**
|
||||
* 项目 Service 实现类
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class ProjectServiceImpl implements ProjectService {
|
||||
|
||||
@Resource
|
||||
private ProjectMapper projectMapper;
|
||||
|
||||
@Override
|
||||
public Long createProject(ProjectSaveReqVO createReqVO) {
|
||||
ProjectDO project = BeanUtils.toBean(createReqVO, ProjectDO.class);
|
||||
projectMapper.insert(project);
|
||||
return project.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProject(ProjectSaveReqVO updateReqVO) {
|
||||
validateProjectExists(updateReqVO.getId());
|
||||
ProjectDO updateObj = BeanUtils.toBean(updateReqVO, ProjectDO.class);
|
||||
projectMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteProject(Long id) {
|
||||
validateProjectExists(id);
|
||||
projectMapper.deleteById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteProjectList(List<Long> ids) {
|
||||
ids.forEach(this::validateProjectExists);
|
||||
projectMapper.deleteBatchIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<ProjectDO> getProjectPage(ProjectPageReqVO pageReqVO) {
|
||||
return projectMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectDO getProject(Long id) {
|
||||
return projectMapper.selectById(id);
|
||||
}
|
||||
|
||||
private void validateProjectExists(Long id) {
|
||||
if (projectMapper.selectById(id) == null) {
|
||||
throw exception(PROJECT_NOT_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.service.specialtyrolesplit;
|
||||
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.specialtyrolesplit.vo.SpecialtyRoleSplitBatchSaveReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.specialtyrolesplit.vo.SpecialtyRoleSplitRespVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 页面5角色比例 Service 接口
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
public interface SpecialtyRoleSplitService {
|
||||
|
||||
List<SpecialtyRoleSplitRespVO> getSpecialtyRoleSplitListByPlanningId(Long planningId);
|
||||
|
||||
void saveSpecialtyRoleSplitBatch(SpecialtyRoleSplitBatchSaveReqVO reqVO);
|
||||
|
||||
void deleteByOutputSplitId(Long outputSplitId);
|
||||
|
||||
void deleteByOutputSplitIds(List<Long> outputSplitIds);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,402 @@
|
||||
package cn.iocoder.lyzsys.module.tjt.service.specialtyrolesplit;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.lyzsys.framework.common.util.json.JsonUtils;
|
||||
import cn.iocoder.lyzsys.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.specialtyrolesplit.vo.SpecialtyRolePersonRespVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.specialtyrolesplit.vo.SpecialtyRolePersonSaveReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.specialtyrolesplit.vo.SpecialtyRoleSplitBatchSaveReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.specialtyrolesplit.vo.SpecialtyRoleSplitRespVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.controller.admin.specialtyrolesplit.vo.SpecialtyRoleSplitSaveItemReqVO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.outputsplit.ProjectOutputSplitDO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planning.ProjectPlanningDO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.project.ProjectDO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.specialtyrolesplit.SpecialtyRoleSplitDO;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.mysql.planning.ProjectPlanningMapper;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.mysql.project.ProjectMapper;
|
||||
import cn.iocoder.lyzsys.module.tjt.dal.mysql.specialtyrolesplit.SpecialtyRoleSplitMapper;
|
||||
import cn.iocoder.lyzsys.module.tjt.enums.OutputSplitBizConstants;
|
||||
import cn.iocoder.lyzsys.module.tjt.service.outputsplit.ProjectOutputSplitService;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.lyzsys.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_NOT_EXISTS;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_OUTPUT_SPLIT_PLANNING_NOT_EXISTS;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.SPECIALTY_ROLE_SPLIT_DESIGN_PERSON_REQUIRED;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.SPECIALTY_ROLE_SPLIT_PERSON_INVALID;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.SPECIALTY_ROLE_SPLIT_PERSON_RATIO_INVALID;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.SPECIALTY_ROLE_SPLIT_ROLE_INVALID;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.SPECIALTY_ROLE_SPLIT_ROLE_RATIO_INVALID;
|
||||
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.SPECIALTY_ROLE_SPLIT_SPECIALTY_INVALID;
|
||||
|
||||
/**
|
||||
* 页面5角色比例 Service 实现类
|
||||
*
|
||||
* @author Codex
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class SpecialtyRoleSplitServiceImpl implements SpecialtyRoleSplitService {
|
||||
|
||||
private static final int RATIO_SCALE = 4;
|
||||
private static final int AMOUNT_SCALE = 2;
|
||||
private static final TypeReference<List<SpecialtyRolePersonSaveReqVO>> PERSON_LIST_TYPE =
|
||||
new TypeReference<List<SpecialtyRolePersonSaveReqVO>>() {};
|
||||
private static final BigDecimal ZERO_RATIO = BigDecimal.ZERO.setScale(RATIO_SCALE, RoundingMode.HALF_UP);
|
||||
private static final BigDecimal ONE_RATIO = BigDecimal.ONE.setScale(RATIO_SCALE, RoundingMode.HALF_UP);
|
||||
private static final BigDecimal ZERO_AMOUNT = BigDecimal.ZERO.setScale(AMOUNT_SCALE, RoundingMode.HALF_UP);
|
||||
|
||||
@Resource
|
||||
private SpecialtyRoleSplitMapper specialtyRoleSplitMapper;
|
||||
@Resource
|
||||
private ProjectOutputSplitService projectOutputSplitService;
|
||||
@Resource
|
||||
private ProjectPlanningMapper projectPlanningMapper;
|
||||
@Resource
|
||||
private ProjectMapper projectMapper;
|
||||
|
||||
@Override
|
||||
public List<SpecialtyRoleSplitRespVO> getSpecialtyRoleSplitListByPlanningId(Long planningId) {
|
||||
ProjectPlanningDO planning = validatePlanningExists(planningId);
|
||||
ProjectDO project = validateProjectExists(planning.getProjectId());
|
||||
ProjectOutputSplitDO outputSplit = projectOutputSplitService.getOrCreateProjectOutputSplit(planningId);
|
||||
List<SpecialtyRoleSplitDO> dbList = specialtyRoleSplitMapper.selectListByOutputSplitId(outputSplit.getId());
|
||||
Map<String, SpecialtyRoleSplitDO> dbMap = dbList.stream().collect(Collectors.toMap(
|
||||
item -> item.getSpecialtyCode() + ":" + item.getRoleCode(), item -> item, (a, b) -> b));
|
||||
List<SpecialtyRoleSplitRespVO> result = new ArrayList<>();
|
||||
BigDecimal assessmentOutputValue = planning.getAssessmentOutputValue();
|
||||
for (OutputSplitBizConstants.SpecialtyItem specialtyItem : OutputSplitBizConstants.SPECIALTY_ITEMS) {
|
||||
BigDecimal specialtyAmount = projectOutputSplitService.getSpecialtyAmount(
|
||||
outputSplit, assessmentOutputValue, specialtyItem.getCode());
|
||||
for (OutputSplitBizConstants.RoleItem roleItem : OutputSplitBizConstants.ROLE_ITEMS) {
|
||||
SpecialtyRoleSplitDO dbItem = dbMap.get(specialtyItem.getCode() + ":" + roleItem.getCode());
|
||||
BigDecimal roleRatio = getStoredRoleRatio(dbItem, roleItem.getCode());
|
||||
BigDecimal roleAmount = multiplyAmount(specialtyAmount, roleRatio);
|
||||
List<SpecialtyRolePersonRespVO> persons = buildRespPersons(dbItem, roleAmount, roleRatio);
|
||||
SpecialtyRoleSplitRespVO respVO = dbItem == null
|
||||
? new SpecialtyRoleSplitRespVO()
|
||||
: BeanUtils.toBean(dbItem, SpecialtyRoleSplitRespVO.class);
|
||||
if (respVO.getId() == null) {
|
||||
respVO.setOutputSplitId(outputSplit.getId());
|
||||
respVO.setSortNo(roleItem.getSortNo());
|
||||
}
|
||||
respVO.setPlanningId(planning.getId());
|
||||
respVO.setProjectName(project.getProjectName());
|
||||
respVO.setPlanningContent(planning.getPlanningContent());
|
||||
respVO.setSpecialtyCode(specialtyItem.getCode());
|
||||
respVO.setSpecialtyName(specialtyItem.getName());
|
||||
respVO.setSpecialtyAmount(specialtyAmount);
|
||||
respVO.setRoleCode(roleItem.getCode());
|
||||
respVO.setRoleName(roleItem.getName());
|
||||
respVO.setRoleRatio(roleRatio);
|
||||
respVO.setRoleAmount(roleAmount);
|
||||
respVO.setPersons(persons);
|
||||
result.add(respVO);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveSpecialtyRoleSplitBatch(SpecialtyRoleSplitBatchSaveReqVO reqVO) {
|
||||
ProjectPlanningDO planning = validatePlanningExists(reqVO.getPlanningId());
|
||||
ProjectOutputSplitDO outputSplit = projectOutputSplitService.getOrCreateProjectOutputSplit(reqVO.getPlanningId());
|
||||
List<SpecialtyRoleSplitDO> dbList = specialtyRoleSplitMapper.selectListByOutputSplitId(outputSplit.getId());
|
||||
Map<String, SpecialtyRoleSplitDO> dbMap = dbList.stream().collect(Collectors.toMap(
|
||||
item -> item.getSpecialtyCode() + ":" + item.getRoleCode(), item -> item, (a, b) -> b));
|
||||
Map<String, Map<String, SpecialtyRoleSplitSaveItemReqVO>> groupedMap = buildGroupedInput(reqVO.getItems());
|
||||
BigDecimal assessmentOutputValue = planning.getAssessmentOutputValue();
|
||||
for (OutputSplitBizConstants.SpecialtyItem specialtyItem : OutputSplitBizConstants.SPECIALTY_ITEMS) {
|
||||
Map<String, SpecialtyRoleSplitSaveItemReqVO> roleMap = groupedMap.getOrDefault(
|
||||
specialtyItem.getCode(), new LinkedHashMap<>());
|
||||
Map<String, BigDecimal> ratioMap = new LinkedHashMap<>();
|
||||
Map<String, List<SpecialtyRolePersonSaveReqVO>> personMap = new LinkedHashMap<>();
|
||||
BigDecimal roleTotal = ZERO_RATIO;
|
||||
BigDecimal specialtyAmount = projectOutputSplitService.getSpecialtyAmount(
|
||||
outputSplit, assessmentOutputValue, specialtyItem.getCode());
|
||||
for (OutputSplitBizConstants.RoleItem roleItem : OutputSplitBizConstants.ROLE_ITEMS) {
|
||||
BigDecimal roleRatio = getSaveRoleRatio(roleMap, roleItem.getCode());
|
||||
BigDecimal roleAmount = multiplyAmount(specialtyAmount, roleRatio);
|
||||
List<SpecialtyRolePersonSaveReqVO> persons = normalizePersons(
|
||||
getSavePersons(roleMap, roleItem.getCode()));
|
||||
validateRolePersons(roleItem.getCode(), roleAmount, persons);
|
||||
ratioMap.put(roleItem.getCode(), roleRatio);
|
||||
personMap.put(roleItem.getCode(), persons);
|
||||
roleTotal = roleTotal.add(roleRatio).setScale(RATIO_SCALE, RoundingMode.HALF_UP);
|
||||
}
|
||||
validateRoleTotal(roleTotal);
|
||||
for (OutputSplitBizConstants.RoleItem roleItem : OutputSplitBizConstants.ROLE_ITEMS) {
|
||||
upsertRole(dbMap, outputSplit.getId(), specialtyItem.getCode(), specialtyItem.getName(),
|
||||
roleItem.getCode(), ratioMap.get(roleItem.getCode()),
|
||||
toPersonJson(personMap.get(roleItem.getCode())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteByOutputSplitId(Long outputSplitId) {
|
||||
specialtyRoleSplitMapper.delete(SpecialtyRoleSplitDO::getOutputSplitId, outputSplitId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteByOutputSplitIds(List<Long> outputSplitIds) {
|
||||
if (outputSplitIds == null || outputSplitIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
specialtyRoleSplitMapper.delete(new cn.iocoder.lyzsys.framework.mybatis.core.query.LambdaQueryWrapperX<SpecialtyRoleSplitDO>()
|
||||
.in(SpecialtyRoleSplitDO::getOutputSplitId, outputSplitIds));
|
||||
}
|
||||
|
||||
private Map<String, Map<String, SpecialtyRoleSplitSaveItemReqVO>> buildGroupedInput(List<SpecialtyRoleSplitSaveItemReqVO> items) {
|
||||
Map<String, Map<String, SpecialtyRoleSplitSaveItemReqVO>> result = new LinkedHashMap<>();
|
||||
for (SpecialtyRoleSplitSaveItemReqVO item : items) {
|
||||
if (!OutputSplitBizConstants.isValidSpecialtyCode(item.getSpecialtyCode())) {
|
||||
throw exception(SPECIALTY_ROLE_SPLIT_SPECIALTY_INVALID);
|
||||
}
|
||||
if (!OutputSplitBizConstants.isValidRoleCode(item.getRoleCode())) {
|
||||
throw exception(SPECIALTY_ROLE_SPLIT_ROLE_INVALID);
|
||||
}
|
||||
result.computeIfAbsent(item.getSpecialtyCode(), key -> new LinkedHashMap<>())
|
||||
.put(item.getRoleCode(), item);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void upsertRole(Map<String, SpecialtyRoleSplitDO> dbMap, Long outputSplitId, String specialtyCode,
|
||||
String specialtyName, String roleCode, BigDecimal roleRatio, String personNames) {
|
||||
String key = specialtyCode + ":" + roleCode;
|
||||
SpecialtyRoleSplitDO dbItem = dbMap.get(key);
|
||||
Integer sortNo = dbItem != null && dbItem.getSortNo() != null
|
||||
? dbItem.getSortNo()
|
||||
: OutputSplitBizConstants.getSpecialtySortNo(specialtyCode) * 10
|
||||
+ OutputSplitBizConstants.getRoleSortNo(roleCode);
|
||||
if (dbItem == null) {
|
||||
SpecialtyRoleSplitDO createObj = new SpecialtyRoleSplitDO();
|
||||
createObj.setOutputSplitId(outputSplitId);
|
||||
createObj.setSpecialtyCode(specialtyCode);
|
||||
createObj.setSpecialtyName(specialtyName);
|
||||
createObj.setRoleCode(roleCode);
|
||||
createObj.setRoleName(OutputSplitBizConstants.getRoleName(roleCode));
|
||||
createObj.setRoleRatio(ratio(roleRatio));
|
||||
createObj.setPersonNames(personNames);
|
||||
createObj.setSortNo(sortNo);
|
||||
specialtyRoleSplitMapper.insert(createObj);
|
||||
return;
|
||||
}
|
||||
SpecialtyRoleSplitDO updateObj = new SpecialtyRoleSplitDO();
|
||||
updateObj.setId(dbItem.getId());
|
||||
updateObj.setOutputSplitId(outputSplitId);
|
||||
updateObj.setSpecialtyCode(specialtyCode);
|
||||
updateObj.setSpecialtyName(specialtyName);
|
||||
updateObj.setRoleCode(roleCode);
|
||||
updateObj.setRoleName(OutputSplitBizConstants.getRoleName(roleCode));
|
||||
updateObj.setRoleRatio(ratio(roleRatio));
|
||||
updateObj.setPersonNames(personNames);
|
||||
updateObj.setSortNo(sortNo);
|
||||
specialtyRoleSplitMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
private List<SpecialtyRolePersonSaveReqVO> getSavePersons(Map<String, SpecialtyRoleSplitSaveItemReqVO> roleMap,
|
||||
String roleCode) {
|
||||
SpecialtyRoleSplitSaveItemReqVO item = roleMap.get(roleCode);
|
||||
return item == null ? new ArrayList<>() : item.getPersons();
|
||||
}
|
||||
|
||||
private BigDecimal getSaveRoleRatio(Map<String, SpecialtyRoleSplitSaveItemReqVO> roleMap, String roleCode) {
|
||||
SpecialtyRoleSplitSaveItemReqVO item = roleMap.get(roleCode);
|
||||
BigDecimal roleRatio = item == null ? ZERO_RATIO : ratio(item.getRoleRatio());
|
||||
if (roleRatio.compareTo(ZERO_RATIO) < 0 || roleRatio.compareTo(ONE_RATIO) > 0) {
|
||||
throw exception(SPECIALTY_ROLE_SPLIT_ROLE_RATIO_INVALID);
|
||||
}
|
||||
return roleRatio;
|
||||
}
|
||||
|
||||
private List<SpecialtyRolePersonSaveReqVO> normalizePersons(List<SpecialtyRolePersonSaveReqVO> persons) {
|
||||
List<SpecialtyRolePersonSaveReqVO> result = new ArrayList<>();
|
||||
if (persons == null || persons.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
for (SpecialtyRolePersonSaveReqVO person : persons) {
|
||||
if (person == null) {
|
||||
continue;
|
||||
}
|
||||
String personName = StrUtil.trim(person.getPersonName());
|
||||
BigDecimal personRatio = person.getPersonRatio();
|
||||
boolean hasName = StrUtil.isNotBlank(personName);
|
||||
boolean hasRatio = personRatio != null;
|
||||
if (!hasName && !hasRatio) {
|
||||
continue;
|
||||
}
|
||||
if (!hasName || !hasRatio) {
|
||||
throw exception(SPECIALTY_ROLE_SPLIT_PERSON_INVALID);
|
||||
}
|
||||
SpecialtyRolePersonSaveReqVO normalized = new SpecialtyRolePersonSaveReqVO();
|
||||
normalized.setPersonName(personName);
|
||||
BigDecimal normalizedRatio = ratio(personRatio);
|
||||
if (normalizedRatio.compareTo(ZERO_RATIO) < 0 || normalizedRatio.compareTo(ONE_RATIO) > 0) {
|
||||
throw exception(SPECIALTY_ROLE_SPLIT_PERSON_RATIO_INVALID);
|
||||
}
|
||||
normalized.setPersonRatio(normalizedRatio);
|
||||
result.add(normalized);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void validateRolePersons(String roleCode, BigDecimal roleAmount, List<SpecialtyRolePersonSaveReqVO> persons) {
|
||||
BigDecimal personTotal = sumPersonRatios(persons);
|
||||
if (personTotal.compareTo(ONE_RATIO) > 0) {
|
||||
throw exception(SPECIALTY_ROLE_SPLIT_PERSON_RATIO_INVALID);
|
||||
}
|
||||
if (OutputSplitBizConstants.ROLE_DESIGN.equals(roleCode)
|
||||
&& roleAmount.compareTo(ZERO_AMOUNT) > 0
|
||||
&& persons.isEmpty()) {
|
||||
throw exception(SPECIALTY_ROLE_SPLIT_DESIGN_PERSON_REQUIRED);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateRoleTotal(BigDecimal roleTotal) {
|
||||
if (ratio(roleTotal).compareTo(ONE_RATIO) != 0) {
|
||||
throw exception(SPECIALTY_ROLE_SPLIT_ROLE_RATIO_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
private BigDecimal getStoredRoleRatio(SpecialtyRoleSplitDO dbItem, String roleCode) {
|
||||
if (dbItem == null) {
|
||||
return OutputSplitBizConstants.ROLE_DESIGN.equals(roleCode) ? ONE_RATIO : ZERO_RATIO;
|
||||
}
|
||||
return ratio(dbItem.getRoleRatio());
|
||||
}
|
||||
|
||||
private List<SpecialtyRolePersonRespVO> buildRespPersons(SpecialtyRoleSplitDO dbItem, BigDecimal roleAmount,
|
||||
BigDecimal roleRatio) {
|
||||
List<SpecialtyRolePersonRespVO> result = new ArrayList<>();
|
||||
for (SpecialtyRolePersonSaveReqVO person : parseStoredPersons(dbItem, roleRatio)) {
|
||||
SpecialtyRolePersonRespVO respVO = new SpecialtyRolePersonRespVO();
|
||||
respVO.setPersonName(person.getPersonName());
|
||||
respVO.setPersonRatio(ratio(person.getPersonRatio()));
|
||||
respVO.setPersonAmount(multiplyAmount(roleAmount, respVO.getPersonRatio()));
|
||||
result.add(respVO);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<SpecialtyRolePersonSaveReqVO> parseStoredPersons(SpecialtyRoleSplitDO dbItem, BigDecimal roleRatio) {
|
||||
List<SpecialtyRolePersonSaveReqVO> result = new ArrayList<>();
|
||||
if (dbItem == null) {
|
||||
return result;
|
||||
}
|
||||
String rawPersons = StrUtil.trimToEmpty(dbItem.getPersonNames());
|
||||
BigDecimal storedRoleRatio = ratio(roleRatio);
|
||||
if (StrUtil.isNotBlank(rawPersons) && JsonUtils.isJson(rawPersons)) {
|
||||
List<SpecialtyRolePersonSaveReqVO> jsonPersons = JsonUtils.parseObjectQuietly(rawPersons, PERSON_LIST_TYPE);
|
||||
if (jsonPersons != null) {
|
||||
for (SpecialtyRolePersonSaveReqVO jsonPerson : jsonPersons) {
|
||||
if (jsonPerson == null) {
|
||||
continue;
|
||||
}
|
||||
String personName = StrUtil.trimToEmpty(jsonPerson.getPersonName());
|
||||
BigDecimal personRatio = jsonPerson.getPersonRatio();
|
||||
if (StrUtil.isBlank(personName) && personRatio == null) {
|
||||
continue;
|
||||
}
|
||||
SpecialtyRolePersonSaveReqVO person = new SpecialtyRolePersonSaveReqVO();
|
||||
person.setPersonName(personName);
|
||||
person.setPersonRatio(ratio(personRatio));
|
||||
result.add(person);
|
||||
}
|
||||
if (!result.isEmpty()) {
|
||||
if (storedRoleRatio.compareTo(ZERO_RATIO) > 0
|
||||
&& sumPersonRatios(result).compareTo(storedRoleRatio) == 0) {
|
||||
return convertLegacyPersons(result, storedRoleRatio);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (StrUtil.isNotBlank(rawPersons)) {
|
||||
result.add(buildStoredPerson(rawPersons, storedRoleRatio.compareTo(ZERO_RATIO) > 0 ? ONE_RATIO : ZERO_RATIO));
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<SpecialtyRolePersonSaveReqVO> convertLegacyPersons(List<SpecialtyRolePersonSaveReqVO> persons,
|
||||
BigDecimal roleRatio) {
|
||||
List<SpecialtyRolePersonSaveReqVO> result = new ArrayList<>();
|
||||
if (roleRatio.compareTo(ZERO_RATIO) <= 0) {
|
||||
return persons;
|
||||
}
|
||||
for (SpecialtyRolePersonSaveReqVO person : persons) {
|
||||
SpecialtyRolePersonSaveReqVO converted = new SpecialtyRolePersonSaveReqVO();
|
||||
converted.setPersonName(person.getPersonName());
|
||||
converted.setPersonRatio(ratio(person.getPersonRatio().divide(roleRatio, RATIO_SCALE, RoundingMode.HALF_UP)));
|
||||
result.add(converted);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private SpecialtyRolePersonSaveReqVO buildStoredPerson(String personName, BigDecimal personRatio) {
|
||||
SpecialtyRolePersonSaveReqVO person = new SpecialtyRolePersonSaveReqVO();
|
||||
person.setPersonName(personName);
|
||||
person.setPersonRatio(ratio(personRatio));
|
||||
return person;
|
||||
}
|
||||
|
||||
private String toPersonJson(List<SpecialtyRolePersonSaveReqVO> persons) {
|
||||
return persons == null || persons.isEmpty() ? null : JsonUtils.toJsonString(persons);
|
||||
}
|
||||
|
||||
private BigDecimal sumPersonRatios(List<SpecialtyRolePersonSaveReqVO> persons) {
|
||||
BigDecimal sum = ZERO_RATIO;
|
||||
if (persons == null || persons.isEmpty()) {
|
||||
return sum;
|
||||
}
|
||||
for (SpecialtyRolePersonSaveReqVO person : persons) {
|
||||
if (person == null) {
|
||||
continue;
|
||||
}
|
||||
sum = sum.add(ratio(person.getPersonRatio())).setScale(RATIO_SCALE, RoundingMode.HALF_UP);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
private ProjectPlanningDO validatePlanningExists(Long planningId) {
|
||||
ProjectPlanningDO planning = projectPlanningMapper.selectById(planningId);
|
||||
if (planning == null) {
|
||||
throw exception(PROJECT_OUTPUT_SPLIT_PLANNING_NOT_EXISTS);
|
||||
}
|
||||
return planning;
|
||||
}
|
||||
|
||||
private ProjectDO validateProjectExists(Long projectId) {
|
||||
ProjectDO project = projectMapper.selectById(projectId);
|
||||
if (project == null) {
|
||||
throw exception(PROJECT_NOT_EXISTS);
|
||||
}
|
||||
return project;
|
||||
}
|
||||
|
||||
private BigDecimal multiplyAmount(BigDecimal left, BigDecimal right) {
|
||||
return amount(left).multiply(ratio(right)).setScale(AMOUNT_SCALE, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private BigDecimal amount(BigDecimal value) {
|
||||
return value == null ? ZERO_AMOUNT : value.setScale(AMOUNT_SCALE, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private BigDecimal ratio(BigDecimal value) {
|
||||
return value == null ? ZERO_RATIO : value.setScale(RATIO_SCALE, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user