Compare commits

...

12 Commits

102 changed files with 4913 additions and 587 deletions

View File

@@ -74,8 +74,9 @@ public class EmployeeController {
@RequestParam(value = "keyword", required = false) String keyword, @RequestParam(value = "keyword", required = false) String keyword,
@RequestParam(value = "officeId", required = false) Long officeId, @RequestParam(value = "officeId", required = false) Long officeId,
@RequestParam(value = "status", required = false) String status, @RequestParam(value = "status", required = false) String status,
@RequestParam(value = "enabledFlag", required = false) Boolean enabledFlag) { @RequestParam(value = "enabledFlag", required = false) Boolean enabledFlag,
return success(employeeService.getEmployeeSimpleList(keyword, officeId, status, enabledFlag)); @RequestParam(value = "officeLeaderFlag", required = false) Boolean officeLeaderFlag) {
return success(employeeService.getEmployeeSimpleList(keyword, officeId, status, enabledFlag, officeLeaderFlag));
} }
} }

View File

@@ -22,4 +22,7 @@ public class EmployeePageReqVO extends PageParam {
@Schema(description = "是否启用", example = "true") @Schema(description = "是否启用", example = "true")
private Boolean enabledFlag; private Boolean enabledFlag;
@Schema(description = "是否所长", example = "false")
private Boolean officeLeaderFlag;
} }

View File

@@ -46,6 +46,9 @@ public class EmployeeRespVO {
@Schema(description = "备注") @Schema(description = "备注")
private String remark; private String remark;
@Schema(description = "是否所长")
private Boolean officeLeaderFlag;
@Schema(description = "排序号") @Schema(description = "排序号")
private Integer sortNo; private Integer sortNo;

View File

@@ -64,6 +64,9 @@ public class EmployeeSaveReqVO {
@Size(max = 255, message = "备注长度不能超过 255 个字符") @Size(max = 255, message = "备注长度不能超过 255 个字符")
private String remark; private String remark;
@Schema(description = "是否所长", example = "false")
private Boolean officeLeaderFlag;
@Schema(description = "排序号", example = "1") @Schema(description = "排序号", example = "1")
private Integer sortNo; private Integer sortNo;

View File

@@ -28,4 +28,7 @@ public class EmployeeSimpleRespVO {
@Schema(description = "职称") @Schema(description = "职称")
private String jobTitle; private String jobTitle;
@Schema(description = "是否所长")
private Boolean officeLeaderFlag;
} }

View File

@@ -2,9 +2,7 @@ package cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearcostbudget;
import cn.iocoder.lyzsys.framework.common.pojo.CommonResult; import cn.iocoder.lyzsys.framework.common.pojo.CommonResult;
import cn.iocoder.lyzsys.framework.common.pojo.PageResult; import cn.iocoder.lyzsys.framework.common.pojo.PageResult;
import cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearcostbudget.vo.EmployeeYearCostBudgetPageReqVO; import cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearcostbudget.vo.*;
import cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearcostbudget.vo.EmployeeYearCostBudgetRespVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearcostbudget.vo.EmployeeYearCostBudgetSaveReqVO;
import cn.iocoder.lyzsys.module.tjt.service.employeeyearcostbudget.EmployeeYearCostBudgetService; import cn.iocoder.lyzsys.module.tjt.service.employeeyearcostbudget.EmployeeYearCostBudgetService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
@@ -34,6 +32,14 @@ public class EmployeeYearCostBudgetController {
return success(employeeYearCostBudgetService.createEmployeeYearCostBudget(createReqVO)); return success(employeeYearCostBudgetService.createEmployeeYearCostBudget(createReqVO));
} }
@PostMapping("/generate")
@Operation(summary = "按年度生成员工年度成本预算")
@PreAuthorize("@ss.hasPermission('tjt:employee-year-cost-budget:create')")
public CommonResult<EmployeeYearCostBudgetGenerateRespVO> generateEmployeeYearCostBudget(
@Valid @RequestBody EmployeeYearCostBudgetGenerateReqVO generateReqVO) {
return success(employeeYearCostBudgetService.generateEmployeeYearCostBudget(generateReqVO));
}
@PutMapping("/update") @PutMapping("/update")
@Operation(summary = "修改员工年度成本预算") @Operation(summary = "修改员工年度成本预算")
@PreAuthorize("@ss.hasPermission('tjt:employee-year-cost-budget:update')") @PreAuthorize("@ss.hasPermission('tjt:employee-year-cost-budget:update')")

View File

@@ -0,0 +1,22 @@
package cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearcostbudget.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
@Schema(description = "管理后台 - 员工年度成本预算按年度生成 Request VO")
@Data
public class EmployeeYearCostBudgetGenerateReqVO {
@Schema(description = "预算年度", requiredMode = Schema.RequiredMode.REQUIRED, example = "2026")
@NotNull(message = "预算年度不能为空")
private Integer budgetYear;
@Schema(description = "默认预计发生成本", example = "0")
@DecimalMin(value = "0", message = "默认预计发生成本不能小于 0")
private BigDecimal expectedCostAmount;
}

View File

@@ -0,0 +1,22 @@
package cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearcostbudget.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 员工年度成本预算按年度生成 Response VO")
@Data
public class EmployeeYearCostBudgetGenerateRespVO {
@Schema(description = "预算年度")
private Integer budgetYear;
@Schema(description = "已启用员工数量")
private Integer totalEnabledEmployeeCount;
@Schema(description = "本次新增预算记录数量")
private Integer createdCount;
@Schema(description = "已存在并跳过的预算记录数量")
private Integer skippedCount;
}

View File

@@ -0,0 +1,78 @@
package cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearleaderoutput;
import cn.iocoder.lyzsys.framework.common.pojo.CommonResult;
import cn.iocoder.lyzsys.framework.common.pojo.PageResult;
import cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearleaderoutput.vo.*;
import cn.iocoder.lyzsys.module.tjt.service.employeeyearleaderoutput.EmployeeYearLeaderOutputService;
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 = "管理后台 - 年度所长考核产值")
@RestController
@RequestMapping("/tjt/employee-year-leader-output")
@Validated
public class EmployeeYearLeaderOutputController {
@Resource
private EmployeeYearLeaderOutputService employeeYearLeaderOutputService;
@PostMapping("/create")
@Operation(summary = "创建年度所长考核产值")
@PreAuthorize("@ss.hasPermission('tjt:employee-year-leader-output:create')")
public CommonResult<Long> createEmployeeYearLeaderOutput(
@Valid @RequestBody EmployeeYearLeaderOutputSaveReqVO createReqVO) {
return success(employeeYearLeaderOutputService.createEmployeeYearLeaderOutput(createReqVO));
}
@PostMapping("/generate")
@Operation(summary = "按年度生成年度所长考核产值")
@PreAuthorize("@ss.hasPermission('tjt:employee-year-leader-output:create')")
public CommonResult<EmployeeYearLeaderOutputGenerateRespVO> generateEmployeeYearLeaderOutput(
@Valid @RequestBody EmployeeYearLeaderOutputGenerateReqVO generateReqVO) {
return success(employeeYearLeaderOutputService.generateEmployeeYearLeaderOutput(generateReqVO));
}
@PutMapping("/update")
@Operation(summary = "修改年度所长考核产值")
@PreAuthorize("@ss.hasPermission('tjt:employee-year-leader-output:update')")
public CommonResult<Boolean> updateEmployeeYearLeaderOutput(
@Valid @RequestBody EmployeeYearLeaderOutputSaveReqVO updateReqVO) {
employeeYearLeaderOutputService.updateEmployeeYearLeaderOutput(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除年度所长考核产值")
@Parameter(name = "id", description = "编号", required = true, example = "1")
@PreAuthorize("@ss.hasPermission('tjt:employee-year-leader-output:delete')")
public CommonResult<Boolean> deleteEmployeeYearLeaderOutput(@RequestParam("id") Long id) {
employeeYearLeaderOutputService.deleteEmployeeYearLeaderOutput(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得年度所长考核产值详情")
@Parameter(name = "id", description = "编号", required = true, example = "1")
@PreAuthorize("@ss.hasPermission('tjt:employee-year-leader-output:query')")
public CommonResult<EmployeeYearLeaderOutputRespVO> getEmployeeYearLeaderOutput(@RequestParam("id") Long id) {
return success(employeeYearLeaderOutputService.getEmployeeYearLeaderOutput(id));
}
@GetMapping("/page")
@Operation(summary = "获得年度所长考核产值分页")
@PreAuthorize("@ss.hasPermission('tjt:employee-year-leader-output:query')")
public CommonResult<PageResult<EmployeeYearLeaderOutputRespVO>> getEmployeeYearLeaderOutputPage(
@Valid EmployeeYearLeaderOutputPageReqVO pageReqVO) {
return success(employeeYearLeaderOutputService.getEmployeeYearLeaderOutputPage(pageReqVO));
}
}

View File

@@ -0,0 +1,22 @@
package cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearleaderoutput.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
@Schema(description = "管理后台 - 年度所长考核产值按年度生成 Request VO")
@Data
public class EmployeeYearLeaderOutputGenerateReqVO {
@Schema(description = "产值年度", requiredMode = Schema.RequiredMode.REQUIRED, example = "2026")
@NotNull(message = "产值年度不能为空")
private Integer outputYear;
@Schema(description = "默认所长考核产值", example = "0")
@DecimalMin(value = "0", message = "默认所长考核产值不能小于 0")
private BigDecimal leaderOutputAmount;
}

View File

@@ -0,0 +1,22 @@
package cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearleaderoutput.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 年度所长考核产值按年度生成 Response VO")
@Data
public class EmployeeYearLeaderOutputGenerateRespVO {
@Schema(description = "产值年度")
private Integer outputYear;
@Schema(description = "已启用所长数量")
private Integer totalEnabledLeaderCount;
@Schema(description = "本次新增记录数量")
private Integer createdCount;
@Schema(description = "已存在并跳过的记录数量")
private Integer skippedCount;
}

View File

@@ -0,0 +1,25 @@
package cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearleaderoutput.vo;
import cn.iocoder.lyzsys.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Schema(description = "管理后台 - 年度所长考核产值分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class EmployeeYearLeaderOutputPageReqVO extends PageParam {
@Schema(description = "员工 ID", example = "1")
private Long employeeId;
@Schema(description = "员工姓名", example = "")
private String employeeName;
@Schema(description = "产值年度", example = "2026")
private Integer outputYear;
@Schema(description = "是否启用", example = "true")
private Boolean enabledFlag;
}

View File

@@ -0,0 +1,40 @@
package cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearleaderoutput.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 EmployeeYearLeaderOutputRespVO {
@Schema(description = "记录 ID", example = "1")
private Long id;
@Schema(description = "员工 ID")
private Long employeeId;
@Schema(description = "员工姓名")
private String employeeName;
@Schema(description = "产值年度")
private Integer outputYear;
@Schema(description = "所长考核产值")
private BigDecimal leaderOutputAmount;
@Schema(description = "备注")
private String remark;
@Schema(description = "排序号")
private Integer sortNo;
@Schema(description = "是否启用")
private Boolean enabledFlag;
@Schema(description = "创建时间")
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,43 @@
package cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearleaderoutput.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.math.BigDecimal;
@Schema(description = "管理后台 - 年度所长考核产值新增/修改 Request VO")
@Data
public class EmployeeYearLeaderOutputSaveReqVO {
@Schema(description = "记录 ID", example = "1")
private Long id;
@Schema(description = "员工 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "员工 ID 不能为空")
private Long employeeId;
@Schema(description = "员工姓名,后端根据 employeeId 回填", example = "张三")
@Size(max = 64, message = "员工姓名长度不能超过 64 个字符")
private String employeeName;
@Schema(description = "产值年度", requiredMode = Schema.RequiredMode.REQUIRED, example = "2026")
@NotNull(message = "产值年度不能为空")
private Integer outputYear;
@Schema(description = "所长考核产值", requiredMode = Schema.RequiredMode.REQUIRED, example = "100000")
@NotNull(message = "所长考核产值不能为空")
private BigDecimal leaderOutputAmount;
@Schema(description = "备注")
@Size(max = 255, message = "备注长度不能超过 255 个字符")
private String remark;
@Schema(description = "排序号", example = "1")
private Integer sortNo;
@Schema(description = "是否启用", example = "true")
private Boolean enabledFlag;
}

View File

@@ -1,9 +1,17 @@
package cn.iocoder.lyzsys.module.tjt.controller.admin.outputsplit; package cn.iocoder.lyzsys.module.tjt.controller.admin.outputsplit;
import cn.iocoder.lyzsys.framework.common.pojo.CommonResult; 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.outputsplit.vo.ProjectOutputSplitPlanningDetailRespVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.outputsplit.vo.ProjectOutputSplitRespVO; 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.controller.admin.outputsplit.vo.ProjectOutputSplitSaveReqVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.planning.vo.ProjectPlanningRespVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.planningquarter.vo.ProjectPlanningQuarterRespVO;
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.service.outputsplit.ProjectOutputSplitService; import cn.iocoder.lyzsys.module.tjt.service.outputsplit.ProjectOutputSplitService;
import cn.iocoder.lyzsys.module.tjt.service.planning.ProjectPlanningService;
import cn.iocoder.lyzsys.module.tjt.service.planningquarter.ProjectPlanningQuarterService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -13,6 +21,14 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static cn.iocoder.lyzsys.framework.common.pojo.CommonResult.success; import static cn.iocoder.lyzsys.framework.common.pojo.CommonResult.success;
@@ -22,8 +38,17 @@ import static cn.iocoder.lyzsys.framework.common.pojo.CommonResult.success;
@Validated @Validated
public class ProjectOutputSplitController { public class ProjectOutputSplitController {
private static final int AMOUNT_SCALE = 2;
private static final int RATIO_SCALE = 4;
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);
@Resource @Resource
private ProjectOutputSplitService projectOutputSplitService; private ProjectOutputSplitService projectOutputSplitService;
@Resource
private ProjectPlanningService projectPlanningService;
@Resource
private ProjectPlanningQuarterService projectPlanningQuarterService;
@GetMapping("/get-by-planning") @GetMapping("/get-by-planning")
@Operation(summary = "根据合约规划获得页面4拆分比例") @Operation(summary = "根据合约规划获得页面4拆分比例")
@@ -33,6 +58,29 @@ public class ProjectOutputSplitController {
return success(projectOutputSplitService.getProjectOutputSplit(planningId)); return success(projectOutputSplitService.getProjectOutputSplit(planningId));
} }
@GetMapping("/planning-detail")
@Operation(summary = "获得页面4合约规划分配聚合详情")
@Parameter(name = "planningId", description = "合约规划 ID", required = true, example = "1")
@PreAuthorize("@ss.hasPermission('tjt:planning:query') && @ss.hasPermission('tjt:output-split:query') && @ss.hasPermission('tjt:planning-quarter:query')")
public CommonResult<ProjectOutputSplitPlanningDetailRespVO> getProjectOutputSplitPlanningDetail(
@RequestParam("planningId") Long planningId) {
ProjectPlanningDO planning = projectPlanningService.getProjectPlanning(planningId);
if (planning == null) {
return success(null);
}
ProjectOutputSplitPlanningDetailRespVO respVO = new ProjectOutputSplitPlanningDetailRespVO();
Map<Long, BigDecimal> allocatedAmountMap =
projectPlanningService.getAllocatedAmountMap(Collections.singleton(planningId));
respVO.setPlanning(BeanUtils.toBean(planning, ProjectPlanningRespVO.class,
planningRespVO -> fillDistributionSummary(planningRespVO, allocatedAmountMap)));
respVO.setOutputSplit(projectOutputSplitService.getProjectOutputSplit(planningId));
List<ProjectPlanningQuarterDO> quarterList =
projectPlanningQuarterService.getProjectPlanningQuarterListByPlanningId(planningId);
respVO.setQuarters(buildPlanningQuarterRespList(planning, quarterList));
return success(respVO);
}
@PutMapping("/save") @PutMapping("/save")
@Operation(summary = "保存页面4拆分比例") @Operation(summary = "保存页面4拆分比例")
@PreAuthorize("@ss.hasPermission('tjt:output-split:update')") @PreAuthorize("@ss.hasPermission('tjt:output-split:update')")
@@ -40,4 +88,72 @@ public class ProjectOutputSplitController {
return success(projectOutputSplitService.saveProjectOutputSplit(reqVO)); return success(projectOutputSplitService.saveProjectOutputSplit(reqVO));
} }
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));
}
private List<ProjectPlanningQuarterRespVO> buildPlanningQuarterRespList(
ProjectPlanningDO planning, List<ProjectPlanningQuarterDO> quarterList) {
if (quarterList == null || quarterList.isEmpty()) {
return Collections.emptyList();
}
boolean hasGuideDetailQuarter = quarterList.stream().anyMatch(item -> item.getGuideDetailId() != null);
if (!hasGuideDetailQuarter) {
return BeanUtils.toBean(quarterList, ProjectPlanningQuarterRespVO.class);
}
BigDecimal baseAmount = amount(planning.getAssessmentOutputValue())
.multiply(ratio(planning.getTotalDistributionAmount()))
.setScale(AMOUNT_SCALE, RoundingMode.HALF_UP);
Map<String, ProjectPlanningQuarterRespVO> aggregateMap = new LinkedHashMap<>();
for (ProjectPlanningQuarterDO quarter : quarterList) {
if (quarter.getGuideDetailId() == null) {
continue;
}
String key = quarter.getDistributionYear() + "_" + quarter.getQuarterNo();
ProjectPlanningQuarterRespVO aggregate = aggregateMap.computeIfAbsent(key, ignored -> {
ProjectPlanningQuarterRespVO item = new ProjectPlanningQuarterRespVO();
item.setPlanningId(planning.getId());
item.setDistributionYear(quarter.getDistributionYear());
item.setQuarterNo(quarter.getQuarterNo());
item.setDistributionAmount(ZERO_AMOUNT);
item.setDistributionRatio(ZERO_RATIO);
return item;
});
BigDecimal distributionAmount = amount(aggregate.getDistributionAmount())
.add(amount(quarter.getDistributionAmount()))
.setScale(AMOUNT_SCALE, RoundingMode.HALF_UP);
aggregate.setDistributionAmount(distributionAmount);
aggregate.setDistributionRatio(amountToDistributionRatio(distributionAmount, baseAmount));
}
List<ProjectPlanningQuarterRespVO> result = new ArrayList<>(aggregateMap.values());
result.sort(Comparator
.comparing(ProjectPlanningQuarterRespVO::getDistributionYear,
Comparator.nullsLast(Integer::compareTo))
.thenComparing(ProjectPlanningQuarterRespVO::getQuarterNo,
Comparator.nullsLast(Integer::compareTo)));
return result;
}
private BigDecimal amountToDistributionRatio(BigDecimal amount, BigDecimal baseAmount) {
if (baseAmount == null || baseAmount.compareTo(BigDecimal.ZERO) == 0) {
return ZERO_RATIO;
}
return amount(amount).divide(baseAmount, RATIO_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);
}
} }

View File

@@ -0,0 +1,24 @@
package cn.iocoder.lyzsys.module.tjt.controller.admin.outputsplit.vo;
import cn.iocoder.lyzsys.module.tjt.controller.admin.planning.vo.ProjectPlanningRespVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.planningquarter.vo.ProjectPlanningQuarterRespVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.Collections;
import java.util.List;
@Schema(description = "管理后台 - 页面4合约规划分配聚合详情 Response VO")
@Data
public class ProjectOutputSplitPlanningDetailRespVO {
@Schema(description = "合约规划详情")
private ProjectPlanningRespVO planning;
@Schema(description = "页面4拆分比例")
private ProjectOutputSplitRespVO outputSplit;
@Schema(description = "季度分配列表")
private List<ProjectPlanningQuarterRespVO> quarters = Collections.emptyList();
}

View File

@@ -4,11 +4,16 @@ import cn.iocoder.lyzsys.framework.common.pojo.CommonResult;
import cn.iocoder.lyzsys.framework.common.pojo.PageResult; import cn.iocoder.lyzsys.framework.common.pojo.PageResult;
import cn.iocoder.lyzsys.framework.common.util.collection.CollectionUtils; import cn.iocoder.lyzsys.framework.common.util.collection.CollectionUtils;
import cn.iocoder.lyzsys.framework.common.util.object.BeanUtils; import cn.iocoder.lyzsys.framework.common.util.object.BeanUtils;
import cn.iocoder.lyzsys.module.tjt.controller.admin.planning.vo.ProjectPlanningOutputEditDetailRespVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.planning.vo.ProjectPlanningPageReqVO; 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.ProjectPlanningRespVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.planning.vo.ProjectPlanningSaveReqVO; import cn.iocoder.lyzsys.module.tjt.controller.admin.planning.vo.ProjectPlanningSaveReqVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.planningguidedetail.vo.ProjectPlanningGuideDetailRespVO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planning.ProjectPlanningDO; import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planning.ProjectPlanningDO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planningguidedetail.ProjectPlanningGuideDetailDO;
import cn.iocoder.lyzsys.module.tjt.enums.ProjectPlanningBizTypeConstants;
import cn.iocoder.lyzsys.module.tjt.service.planning.ProjectPlanningService; import cn.iocoder.lyzsys.module.tjt.service.planning.ProjectPlanningService;
import cn.iocoder.lyzsys.module.tjt.service.planningguidedetail.ProjectPlanningGuideDetailService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -37,6 +42,8 @@ public class ProjectPlanningController {
@Resource @Resource
private ProjectPlanningService projectPlanningService; private ProjectPlanningService projectPlanningService;
@Resource
private ProjectPlanningGuideDetailService projectPlanningGuideDetailService;
@PostMapping("/create") @PostMapping("/create")
@Operation(summary = "创建合约规划") @Operation(summary = "创建合约规划")
@@ -97,6 +104,30 @@ public class ProjectPlanningController {
respVO -> fillDistributionSummary(respVO, allocatedAmountMap))); respVO -> fillDistributionSummary(respVO, allocatedAmountMap)));
} }
@GetMapping("/output-edit-detail")
@Operation(summary = "获得合约规划测算参数编辑详情")
@Parameter(name = "id", description = "编号", required = true, example = "1")
@PreAuthorize("@ss.hasPermission('tjt:planning:query')")
public CommonResult<ProjectPlanningOutputEditDetailRespVO> getProjectPlanningOutputEditDetail(@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()));
ProjectPlanningOutputEditDetailRespVO respVO = new ProjectPlanningOutputEditDetailRespVO();
respVO.setPlanning(BeanUtils.toBean(planning, ProjectPlanningRespVO.class,
planningRespVO -> fillDistributionSummary(planningRespVO, allocatedAmountMap)));
if (ProjectPlanningBizTypeConstants.isMajorGuidanceScene(
planning.getOwnershipType(), planning.getCalculationMethod())) {
List<ProjectPlanningGuideDetailDO> guideDetails =
projectPlanningGuideDetailService.getProjectPlanningGuideDetailListByPlanningId(id);
respVO.setGuideDetails(BeanUtils.toBean(guideDetails, ProjectPlanningGuideDetailRespVO.class));
}
return success(respVO);
}
@GetMapping("/list-by-project") @GetMapping("/list-by-project")
@Operation(summary = "根据项目获得合约规划列表") @Operation(summary = "根据项目获得合约规划列表")
@Parameter(name = "projectId", description = "项目 ID", required = true, example = "1") @Parameter(name = "projectId", description = "项目 ID", required = true, example = "1")

View File

@@ -0,0 +1,20 @@
package cn.iocoder.lyzsys.module.tjt.controller.admin.planning.vo;
import cn.iocoder.lyzsys.module.tjt.controller.admin.planningguidedetail.vo.ProjectPlanningGuideDetailRespVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.Collections;
import java.util.List;
@Schema(description = "管理后台 - 合约规划测算参数编辑聚合详情 Response VO")
@Data
public class ProjectPlanningOutputEditDetailRespVO {
@Schema(description = "合约规划详情")
private ProjectPlanningRespVO planning;
@Schema(description = "指导价法明细列表,仅专业所 + 指导价法场景返回")
private List<ProjectPlanningGuideDetailRespVO> guideDetails = Collections.emptyList();
}

View File

@@ -18,10 +18,10 @@ public class ProjectPlanningPageReqVO extends PageParam {
@Schema(description = "项目 ID", example = "1") @Schema(description = "项目 ID", example = "1")
private Long projectId; private Long projectId;
@Schema(description = "归属类型", example = "专业所") @Schema(description = "归属类型", example = "major")
private String ownershipType; private String ownershipType;
@Schema(description = "产值计算方式", example = "指导价法") @Schema(description = "产值计算方式", example = "guidance_price")
private String calculationMethod; private String calculationMethod;
@Schema(description = "项目任务包,模糊匹配", example = "建筑") @Schema(description = "项目任务包,模糊匹配", example = "建筑")

View File

@@ -17,7 +17,7 @@ public class ProjectPlanningRespVO {
private Long projectId; private Long projectId;
@Schema(description = "排序") @Schema(description = "排序")
private Integer sortNo; private String sortNo;
@Schema(description = "归属类型") @Schema(description = "归属类型")
private String ownershipType; private String ownershipType;

View File

@@ -21,15 +21,16 @@ public class ProjectPlanningSaveReqVO {
@NotNull(message = "项目 ID 不能为空") @NotNull(message = "项目 ID 不能为空")
private Long projectId; private Long projectId;
@Schema(description = "排序", example = "0") @Schema(description = "排序", example = "A-01")
private Integer sortNo; @Size(max = 50, message = "排序长度不能超过 50 个字符")
private String sortNo;
@Schema(description = "归属类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "专业所") @Schema(description = "归属类型major/comprehensive/special_subcontract_major/special_subcontract_source_coop/special_subcontract_comprehensive", requiredMode = Schema.RequiredMode.REQUIRED, example = "major")
@NotBlank(message = "归属类型不能为空") @NotBlank(message = "归属类型不能为空")
@Size(max = 20, message = "归属类型长度不能超过 20 个字符") @Size(max = 64, message = "归属类型长度不能超过 64 个字符")
private String ownershipType; private String ownershipType;
@Schema(description = "产值计算方式,页面 2 维护", example = "指导价法") @Schema(description = "产值计算方式guidance_price/contract_price/virtual_output,页面 2 维护", example = "guidance_price")
@Size(max = 30, message = "产值计算方式长度不能超过 30 个字符") @Size(max = 30, message = "产值计算方式长度不能超过 30 个字符")
private String calculationMethod; private String calculationMethod;
@@ -73,7 +74,7 @@ public class ProjectPlanningSaveReqVO {
@Schema(description = "面积", example = "30000") @Schema(description = "面积", example = "30000")
private BigDecimal planningArea; private BigDecimal planningArea;
@Schema(description = "设计阶段", example = "方案设计") @Schema(description = "设计阶段scheme/construction_drawing/scheme_and_construction_drawing", example = "scheme")
@Size(max = 50, message = "设计阶段长度不能超过 50 个字符") @Size(max = 50, message = "设计阶段长度不能超过 50 个字符")
private String designStage; private String designStage;
@@ -119,7 +120,7 @@ public class ProjectPlanningSaveReqVO {
@Schema(description = "内部指导单价(元/m²", example = "80.00") @Schema(description = "内部指导单价(元/m²", example = "80.00")
private BigDecimal internalGuidanceUnitPrice; private BigDecimal internalGuidanceUnitPrice;
@Schema(description = "虚拟产值计算方式:指导单价法/指导总价法/工日法", example = "工日法") @Schema(description = "虚拟产值计算方式:guidance_price/guidance_total_price/working_day", example = "working_day")
@Size(max = 30, message = "虚拟产值计算方式长度不能超过 30 个字符") @Size(max = 30, message = "虚拟产值计算方式长度不能超过 30 个字符")
private String virtualCalculationMethod; private String virtualCalculationMethod;
@@ -140,4 +141,8 @@ public class ProjectPlanningSaveReqVO {
@DecimalMax(value = "1.0000", message = "calculationRatio must be <= 1") @DecimalMax(value = "1.0000", message = "calculationRatio must be <= 1")
private BigDecimal calculationRatio; private BigDecimal calculationRatio;
@Schema(description = "合同单价(元/m²为空时系统按分项合同产值 / 面积计算", example = "120.00")
@DecimalMin(value = "0.0000", message = "contractUnitPrice must be >= 0")
private BigDecimal contractUnitPrice;
} }

View File

@@ -22,7 +22,7 @@ public class ProjectPlanningGuideDetailRespVO {
@Schema(description = "设计部位") @Schema(description = "设计部位")
private String designPart; private String designPart;
@Schema(description = "建筑类型") @Schema(description = "设计内容/设计类型")
private String buildingType; private String buildingType;
@Schema(description = "设计面积") @Schema(description = "设计面积")

View File

@@ -17,14 +17,14 @@ public class ProjectPlanningGuideDetailSaveReqVO {
@Schema(description = "明细 ID", example = "1") @Schema(description = "明细 ID", example = "1")
private Long id; private Long id;
@Schema(description = "设计部位", requiredMode = Schema.RequiredMode.REQUIRED, example = "地上部分") @Schema(description = "设计部位above_ground/underground/other", requiredMode = Schema.RequiredMode.REQUIRED, example = "above_ground")
@NotBlank(message = "设计部位不能为空") @NotBlank(message = "设计部位不能为空")
@Size(max = 20, message = "设计部位长度不能超过 20 个字符") @Size(max = 20, message = "设计部位长度不能超过 20 个字符")
private String designPart; private String designPart;
@Schema(description = "建筑类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "住宅") @Schema(description = "设计内容/设计类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "住宅")
@NotBlank(message = "建筑类型不能为空") @NotBlank(message = "设计内容/设计类型不能为空")
@Size(max = 100, message = "建筑类型长度不能超过 100 个字符") @Size(max = 100, message = "设计内容/设计类型长度不能超过 100 个字符")
private String buildingType; private String buildingType;
@Schema(description = "设计面积", requiredMode = Schema.RequiredMode.REQUIRED, example = "12000") @Schema(description = "设计面积", requiredMode = Schema.RequiredMode.REQUIRED, example = "12000")

View File

@@ -2,9 +2,17 @@ package cn.iocoder.lyzsys.module.tjt.controller.admin.planningquarter;
import cn.iocoder.lyzsys.framework.common.pojo.CommonResult; import cn.iocoder.lyzsys.framework.common.pojo.CommonResult;
import cn.iocoder.lyzsys.framework.common.util.object.BeanUtils; import cn.iocoder.lyzsys.framework.common.util.object.BeanUtils;
import cn.iocoder.lyzsys.module.tjt.controller.admin.planning.vo.ProjectPlanningRespVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.planningquarter.vo.ProjectPlanningQuarterGuideDetailRespVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.planningquarter.vo.ProjectPlanningQuarterPlanningDetailRespVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.planningquarter.vo.ProjectPlanningQuarterRespVO; 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.controller.admin.planningquarter.vo.ProjectPlanningQuarterSaveReqVO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planning.ProjectPlanningDO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planningguidedetail.ProjectPlanningGuideDetailDO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planningquarter.ProjectPlanningQuarterDO; import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planningquarter.ProjectPlanningQuarterDO;
import cn.iocoder.lyzsys.module.tjt.enums.ProjectPlanningBizTypeConstants;
import cn.iocoder.lyzsys.module.tjt.service.planning.ProjectPlanningService;
import cn.iocoder.lyzsys.module.tjt.service.planningguidedetail.ProjectPlanningGuideDetailService;
import cn.iocoder.lyzsys.module.tjt.service.planningquarter.ProjectPlanningQuarterService; import cn.iocoder.lyzsys.module.tjt.service.planningquarter.ProjectPlanningQuarterService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
@@ -15,7 +23,14 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import static cn.iocoder.lyzsys.framework.common.pojo.CommonResult.success; import static cn.iocoder.lyzsys.framework.common.pojo.CommonResult.success;
@@ -25,8 +40,15 @@ import static cn.iocoder.lyzsys.framework.common.pojo.CommonResult.success;
@Validated @Validated
public class ProjectPlanningQuarterController { public class ProjectPlanningQuarterController {
private static final int RATIO_SCALE = 4;
private static final BigDecimal ZERO_RATIO = BigDecimal.ZERO.setScale(RATIO_SCALE, RoundingMode.HALF_UP);
@Resource @Resource
private ProjectPlanningQuarterService projectPlanningQuarterService; private ProjectPlanningQuarterService projectPlanningQuarterService;
@Resource
private ProjectPlanningService projectPlanningService;
@Resource
private ProjectPlanningGuideDetailService projectPlanningGuideDetailService;
@PostMapping("/create") @PostMapping("/create")
@Operation(summary = "创建季度分配") @Operation(summary = "创建季度分配")
@@ -80,4 +102,109 @@ public class ProjectPlanningQuarterController {
return success(BeanUtils.toBean(list, ProjectPlanningQuarterRespVO.class)); return success(BeanUtils.toBean(list, ProjectPlanningQuarterRespVO.class));
} }
@GetMapping("/planning-detail")
@Operation(summary = "获得合约规划详情及季度分配列表")
@Parameter(name = "planningId", description = "合约规划 ID", required = true, example = "1")
@PreAuthorize("@ss.hasPermission('tjt:planning:query') && @ss.hasPermission('tjt:planning-quarter:query')")
public CommonResult<ProjectPlanningQuarterPlanningDetailRespVO> getProjectPlanningQuarterPlanningDetail(
@RequestParam("planningId") Long planningId) {
ProjectPlanningDO planning = projectPlanningService.getProjectPlanning(planningId);
if (planning == null) {
return success(null);
}
List<ProjectPlanningQuarterDO> quarterList =
projectPlanningQuarterService.getProjectPlanningQuarterListByPlanningId(planningId);
ProjectPlanningQuarterPlanningDetailRespVO respVO = new ProjectPlanningQuarterPlanningDetailRespVO();
Map<Long, BigDecimal> allocatedAmountMap =
projectPlanningService.getAllocatedAmountMap(Collections.singleton(planningId));
respVO.setPlanning(BeanUtils.toBean(planning, ProjectPlanningRespVO.class,
planningRespVO -> fillDistributionSummary(planningRespVO, allocatedAmountMap)));
List<ProjectPlanningQuarterDO> parentQuarterList = quarterList.stream()
.filter(item -> item.getGuideDetailId() == null)
.collect(Collectors.toList());
List<ProjectPlanningQuarterDO> detailQuarterList = quarterList.stream()
.filter(item -> item.getGuideDetailId() != null)
.collect(Collectors.toList());
boolean guideDetailMode = ProjectPlanningBizTypeConstants.isMajorGuidanceScene(
planning.getOwnershipType(), planning.getCalculationMethod());
respVO.setGuideDetailMode(guideDetailMode);
respVO.setParentQuarters(BeanUtils.toBean(parentQuarterList, ProjectPlanningQuarterRespVO.class));
respVO.setQuarters(guideDetailMode
? respVO.getParentQuarters()
: BeanUtils.toBean(quarterList, ProjectPlanningQuarterRespVO.class));
if (guideDetailMode) {
List<ProjectPlanningGuideDetailDO> guideDetailList =
projectPlanningGuideDetailService.getProjectPlanningGuideDetailListByPlanningId(planningId);
respVO.setGuideDetails(buildGuideDetailRespList(planning, guideDetailList, detailQuarterList));
boolean historyParentMode = !parentQuarterList.isEmpty() && detailQuarterList.isEmpty();
respVO.setHistoryParentMode(historyParentMode);
if (historyParentMode) {
respVO.setMessage("当前合约规划存在历史父级季度分配。请先清空历史父级分配后,再按指导价法明细维护。");
}
}
return success(respVO);
}
private List<ProjectPlanningQuarterGuideDetailRespVO> buildGuideDetailRespList(
ProjectPlanningDO planning,
List<ProjectPlanningGuideDetailDO> guideDetailList,
List<ProjectPlanningQuarterDO> detailQuarterList) {
if (guideDetailList == null || guideDetailList.isEmpty()) {
return Collections.emptyList();
}
Map<Long, List<ProjectPlanningQuarterDO>> quarterMap = detailQuarterList == null
? Collections.emptyMap()
: detailQuarterList.stream()
.filter(item -> item.getGuideDetailId() != null)
.collect(Collectors.groupingBy(ProjectPlanningQuarterDO::getGuideDetailId));
List<ProjectPlanningQuarterGuideDetailRespVO> result = new ArrayList<>();
for (ProjectPlanningGuideDetailDO guideDetail : guideDetailList) {
ProjectPlanningQuarterGuideDetailRespVO respVO =
BeanUtils.toBean(guideDetail, ProjectPlanningQuarterGuideDetailRespVO.class);
List<ProjectPlanningQuarterDO> quarterList =
quarterMap.getOrDefault(guideDetail.getId(), Collections.emptyList());
respVO.setQuarters(BeanUtils.toBean(quarterList, ProjectPlanningQuarterRespVO.class));
fillGuideDetailDistributionSummary(respVO, planning, quarterList);
result.add(respVO);
}
return result;
}
private void fillGuideDetailDistributionSummary(ProjectPlanningQuarterGuideDetailRespVO respVO,
ProjectPlanningDO planning,
List<ProjectPlanningQuarterDO> quarterList) {
BigDecimal allocatedRatio = ZERO_RATIO;
if (quarterList != null) {
for (ProjectPlanningQuarterDO quarter : quarterList) {
allocatedRatio = allocatedRatio.add(ratio(quarter.getDistributionRatio()))
.setScale(RATIO_SCALE, RoundingMode.HALF_UP);
}
}
BigDecimal totalDistributionAmount = planning.getTotalDistributionAmount() == null
? BigDecimal.ONE.setScale(RATIO_SCALE, RoundingMode.HALF_UP)
: planning.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)
.max(BigDecimal.ZERO)
.setScale(RATIO_SCALE, RoundingMode.HALF_UP));
}
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));
}
private BigDecimal ratio(BigDecimal value) {
return value == null ? ZERO_RATIO : value.setScale(RATIO_SCALE, RoundingMode.HALF_UP);
}
} }

View File

@@ -0,0 +1,26 @@
package cn.iocoder.lyzsys.module.tjt.controller.admin.planningquarter.vo;
import cn.iocoder.lyzsys.module.tjt.controller.admin.planningguidedetail.vo.ProjectPlanningGuideDetailRespVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
@Schema(description = "管理后台 - 指导价法明细季度分配 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class ProjectPlanningQuarterGuideDetailRespVO extends ProjectPlanningGuideDetailRespVO {
@Schema(description = "明细已分配比例")
private BigDecimal allocatedAmount;
@Schema(description = "明细待分配比例")
private BigDecimal pendingAmount;
@Schema(description = "明细季度分配列表")
private List<ProjectPlanningQuarterRespVO> quarters = Collections.emptyList();
}

View File

@@ -0,0 +1,35 @@
package cn.iocoder.lyzsys.module.tjt.controller.admin.planningquarter.vo;
import cn.iocoder.lyzsys.module.tjt.controller.admin.planning.vo.ProjectPlanningRespVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.Collections;
import java.util.List;
@Schema(description = "管理后台 - 合约规划季度分配聚合详情 Response VO")
@Data
public class ProjectPlanningQuarterPlanningDetailRespVO {
@Schema(description = "合约规划详情")
private ProjectPlanningRespVO planning;
@Schema(description = "季度分配列表")
private List<ProjectPlanningQuarterRespVO> quarters = Collections.emptyList();
@Schema(description = "是否指导价法明细分配模式")
private Boolean guideDetailMode = Boolean.FALSE;
@Schema(description = "是否存在历史父级季度分配")
private Boolean historyParentMode = Boolean.FALSE;
@Schema(description = "提示信息")
private String message;
@Schema(description = "父级季度分配列表")
private List<ProjectPlanningQuarterRespVO> parentQuarters = Collections.emptyList();
@Schema(description = "指导价法明细及各自季度分配列表")
private List<ProjectPlanningQuarterGuideDetailRespVO> guideDetails = Collections.emptyList();
}

View File

@@ -16,6 +16,12 @@ public class ProjectPlanningQuarterRespVO {
@Schema(description = "Planning ID", example = "1") @Schema(description = "Planning ID", example = "1")
private Long planningId; private Long planningId;
@Schema(description = "Guide detail ID")
private Long guideDetailId;
@Schema(description = "Guide detail sort number snapshot")
private Integer guideDetailSortNo;
@Schema(description = "Distribution year") @Schema(description = "Distribution year")
private Integer distributionYear; private Integer distributionYear;

View File

@@ -19,6 +19,12 @@ public class ProjectPlanningQuarterSaveReqVO {
@NotNull(message = "planningId cannot be null") @NotNull(message = "planningId cannot be null")
private Long planningId; private Long planningId;
@Schema(description = "Guide detail ID, required only for major + guidance price planning", example = "1")
private Long guideDetailId;
@Schema(description = "Guide detail sort number snapshot", example = "1")
private Integer guideDetailSortNo;
@Schema(description = "Distribution year", requiredMode = Schema.RequiredMode.REQUIRED, example = "2026") @Schema(description = "Distribution year", requiredMode = Schema.RequiredMode.REQUIRED, example = "2026")
@NotNull(message = "distributionYear cannot be null") @NotNull(message = "distributionYear cannot be null")
private Integer distributionYear; private Integer distributionYear;

View File

@@ -4,6 +4,7 @@ import cn.iocoder.lyzsys.framework.common.pojo.CommonResult;
import cn.iocoder.lyzsys.framework.common.pojo.PageResult; 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.ProjectProfitPageReqVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.profit.vo.ProjectProfitRespVO; import cn.iocoder.lyzsys.module.tjt.controller.admin.profit.vo.ProjectProfitRespVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.profit.vo.ProjectProfitSettlementSaveReqVO;
import cn.iocoder.lyzsys.module.tjt.service.profit.ProjectProfitService; import cn.iocoder.lyzsys.module.tjt.service.profit.ProjectProfitService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
@@ -11,6 +12,9 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@@ -44,4 +48,27 @@ public class ProjectProfitController {
return success(projectProfitService.getProjectProfitPage(pageReqVO)); return success(projectProfitService.getProjectProfitPage(pageReqVO));
} }
@PostMapping("/lock-budget")
@Operation(summary = "锁定项目成本预算测算")
@Parameter(name = "projectId", description = "项目 ID", required = true, example = "1")
@PreAuthorize("@ss.hasPermission('tjt:profit:query')")
public CommonResult<ProjectProfitRespVO> lockBudgetSnapshot(@RequestParam("projectId") Long projectId) {
return success(projectProfitService.lockBudgetSnapshot(projectId));
}
@PostMapping("/lock-accounting")
@Operation(summary = "锁定项目成本核算测算")
@Parameter(name = "projectId", description = "项目 ID", required = true, example = "1")
@PreAuthorize("@ss.hasPermission('tjt:profit:query')")
public CommonResult<ProjectProfitRespVO> lockAccountingSnapshot(@RequestParam("projectId") Long projectId) {
return success(projectProfitService.lockAccountingSnapshot(projectId));
}
@PutMapping("/save-settlement")
@Operation(summary = "保存项目成本结算测算")
@PreAuthorize("@ss.hasPermission('tjt:profit:query')")
public CommonResult<ProjectProfitRespVO> saveSettlementSnapshot(@Valid @RequestBody ProjectProfitSettlementSaveReqVO saveReqVO) {
return success(projectProfitService.saveSettlementSnapshot(saveReqVO));
}
} }

View File

@@ -17,27 +17,39 @@ public class ProjectProfitRespVO {
private String projectName; private String projectName;
@Schema(description = "排序") @Schema(description = "排序")
private Integer sortNo; private String sortNo;
@Schema(description = "是否签订合同") @Schema(description = "是否签订合同")
private Boolean contractSignedFlag; private Boolean contractSignedFlag;
@Schema(description = "合同产值") @Schema(description = "合同产值")
private BigDecimal contractAmount; private BigDecimal contractAmount;
@Schema(description = "最终结算金额") @Schema(description = "结算合同总产值")
private BigDecimal finalSettlementAmount; private BigDecimal finalSettlementAmount;
@Schema(description = "综合所协作金额") @Schema(description = "合同产值(不含增值税),合同总产值 / 1.06")
private BigDecimal effectiveSettlementAmount;
@Schema(description = "综合所人工成本")
private BigDecimal comprehensivePlanningAmount; private BigDecimal comprehensivePlanningAmount;
@Schema(description = "分包金额") @Schema(description = "分包人工成本合计")
private BigDecimal subcontractPlanningAmount; private BigDecimal subcontractPlanningAmount;
@Schema(description = "业所产值") @Schema(description = "项分包-专业所人工成本")
private BigDecimal specialSubcontractPlanningAmount;
@Schema(description = "专项分包-源头合作分包人工成本")
private BigDecimal sourceCoopSubcontractPlanningAmount;
@Schema(description = "专项分包-综合所人工成本")
private BigDecimal comprehensiveSubcontractPlanningAmount;
@Schema(description = "专业所考核产值")
private BigDecimal majorOutputValue; private BigDecimal majorOutputValue;
@Schema(description = "专业所预计绩效") @Schema(description = "专业所人工成本")
private BigDecimal majorExpectedPerformance; private BigDecimal majorExpectedPerformance;
@Schema(description = "科创产值比例") @Schema(description = "科创产值比例")
@@ -49,10 +61,10 @@ public class ProjectProfitRespVO {
@Schema(description = "其他成本") @Schema(description = "其他成本")
private BigDecimal otherCost; private BigDecimal otherCost;
@Schema(description = "盈亏值") @Schema(description = "预算盈亏值")
private BigDecimal profitLossValue; private BigDecimal profitLossValue;
@Schema(description = "盈亏百分比") @Schema(description = "预算盈亏百分比")
private BigDecimal profitLossRate; private BigDecimal profitLossRate;
@Schema(description = "项目开始年度") @Schema(description = "项目开始年度")
@@ -61,4 +73,13 @@ public class ProjectProfitRespVO {
@Schema(description = "创建时间") @Schema(description = "创建时间")
private LocalDateTime createTime; private LocalDateTime createTime;
@Schema(description = "项目成本预算测算快照")
private ProjectProfitSnapshotRespVO budgetSnapshot;
@Schema(description = "项目成本核算测算快照")
private ProjectProfitSnapshotRespVO accountingSnapshot;
@Schema(description = "项目成本结算测算快照")
private ProjectProfitSnapshotRespVO settlementSnapshot;
} }

View File

@@ -0,0 +1,25 @@
package cn.iocoder.lyzsys.module.tjt.controller.admin.profit.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
@Schema(description = "管理后台 - 项目成本结算测算保存 Request VO")
@Data
public class ProjectProfitSettlementSaveReqVO {
@Schema(description = "项目 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "项目 ID 不能为空")
private Long projectId;
@Schema(description = "考核结果")
@Size(max = 64, message = "考核结果长度不能超过 64 个字符")
private String assessmentResult;
@Schema(description = "备注")
@Size(max = 500, message = "备注长度不能超过 500 个字符")
private String remark;
}

View File

@@ -0,0 +1,100 @@
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 ProjectProfitSnapshotRespVO {
@Schema(description = "快照 ID")
private Long id;
@Schema(description = "项目 ID")
private Long projectId;
@Schema(description = "快照类型budget/accounting/settlement")
private String snapshotType;
@Schema(description = "是否锁定")
private Boolean lockedFlag;
@Schema(description = "操作人 ID")
private Long actionUserId;
@Schema(description = "操作人姓名")
private String actionUserName;
@Schema(description = "操作时间")
private LocalDateTime actionTime;
@Schema(description = "合同总产值")
private BigDecimal contractAmount;
@Schema(description = "结算合同总产值")
private BigDecimal finalSettlementAmount;
@Schema(description = "合同产值(不含增值税),合同总产值 / 1.06")
private BigDecimal effectiveSettlementAmount;
@Schema(description = "综合所人工成本")
private BigDecimal comprehensivePlanningAmount;
@Schema(description = "专项分包人工成本合计")
private BigDecimal subcontractPlanningAmount;
@Schema(description = "专项分包-专业所人工成本")
private BigDecimal specialSubcontractPlanningAmount;
@Schema(description = "专项分包-源头合作分包人工成本")
private BigDecimal sourceCoopSubcontractPlanningAmount;
@Schema(description = "专项分包-综合所人工成本")
private BigDecimal comprehensiveSubcontractPlanningAmount;
@Schema(description = "专业所考核产值")
private BigDecimal majorOutputValue;
@Schema(description = "专业所人工成本")
private BigDecimal majorExpectedPerformance;
@Schema(description = "科创产值比例")
private BigDecimal innovationOutputRate;
@Schema(description = "科创产值")
private BigDecimal innovationOutputValue;
@Schema(description = "其他成本")
private BigDecimal otherCost;
@Schema(description = "预算盈亏值")
private BigDecimal profitLossValue;
@Schema(description = "预算盈亏百分比")
private BigDecimal profitLossRate;
@Schema(description = "考核结果")
private String assessmentResult;
@Schema(description = "考核系数")
private BigDecimal assessmentCoefficient;
@Schema(description = "综合所考核产值核算值")
private BigDecimal comprehensiveAccountingOutputValue;
@Schema(description = "综合所考核产值结算值")
private BigDecimal comprehensiveSettlementOutputValue;
@Schema(description = "专业所考核产值核算值")
private BigDecimal majorAccountingOutputValue;
@Schema(description = "专业所考核产值结算值")
private BigDecimal majorSettlementOutputValue;
@Schema(description = "备注")
private String remark;
}

View File

@@ -24,7 +24,7 @@ public class ProjectPageReqVO extends PageParam {
@Schema(description = "项目开始年度", example = "2026") @Schema(description = "项目开始年度", example = "2026")
private Integer projectStartYear; private Integer projectStartYear;
@Schema(description = "项目状态", example = "进行中") @Schema(description = "项目状态in_progress/completed/paused/terminated", example = "in_progress")
private String projectStatus; private String projectStatus;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)

View File

@@ -28,18 +28,18 @@ public class ProjectRespVO {
@Schema(description = "排序") @Schema(description = "排序")
@ExcelProperty("排序") @ExcelProperty("排序")
private Integer sortNo; private String sortNo;
@Schema(description = "是否签订合同", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "是否签订合同", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("是否签订合同") @ExcelProperty("是否签订合同")
private Boolean contractSignedFlag; private Boolean contractSignedFlag;
@Schema(description = "合同产值", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "合同产值", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("合同产值") @ExcelProperty("合同产值")
private BigDecimal contractAmount; private BigDecimal contractAmount;
@Schema(description = "工程总面积", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "建筑面积", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("工程总面积") @ExcelProperty("建筑面积")
private BigDecimal totalConstructionArea; private BigDecimal totalConstructionArea;
@Schema(description = "建设单位") @Schema(description = "建设单位")
@@ -71,8 +71,8 @@ public class ProjectRespVO {
@ExcelProperty("工程类型") @ExcelProperty("工程类型")
private String projectType; private String projectType;
@Schema(description = "工程类别") @Schema(description = "设计类型")
@ExcelProperty("工程类别") @ExcelProperty("设计类型")
private String projectCategory; private String projectCategory;
@Schema(description = "项目开始年度") @Schema(description = "项目开始年度")
@@ -95,8 +95,8 @@ public class ProjectRespVO {
@Schema(description = "中止原因") @Schema(description = "中止原因")
private String terminateReason; private String terminateReason;
@Schema(description = "最终结算金额") @Schema(description = "结算合同总产值")
@ExcelProperty("最终结算金额") @ExcelProperty("结算合同总产值")
private BigDecimal finalSettlementAmount; private BigDecimal finalSettlementAmount;
@Schema(description = "科创产值比例") @Schema(description = "科创产值比例")

View File

@@ -28,19 +28,20 @@ public class ProjectSaveReqVO {
@Size(max = 200, message = "项目名称长度不能超过 200 个字符") @Size(max = 200, message = "项目名称长度不能超过 200 个字符")
private String projectName; private String projectName;
@Schema(description = "排序", example = "0") @Schema(description = "排序", example = "A-01")
private Integer sortNo; @Size(max = 50, message = "排序长度不能超过 50 个字符")
private String sortNo;
@Schema(description = "是否签订合同", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") @Schema(description = "是否签订合同", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
@NotNull(message = "是否签订合同不能为空") @NotNull(message = "是否签订合同不能为空")
private Boolean contractSignedFlag; private Boolean contractSignedFlag;
@Schema(description = "合同产值", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000000") @Schema(description = "合同产值", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000000")
@NotNull(message = "合同产值不能为空") @NotNull(message = "合同产值不能为空")
private BigDecimal contractAmount; private BigDecimal contractAmount;
@Schema(description = "工程总面积", requiredMode = Schema.RequiredMode.REQUIRED, example = "30000") @Schema(description = "建筑面积", requiredMode = Schema.RequiredMode.REQUIRED, example = "30000")
@NotNull(message = "工程总面积不能为空") @NotNull(message = "建筑面积不能为空")
private BigDecimal totalConstructionArea; private BigDecimal totalConstructionArea;
@Schema(description = "建设单位", example = "XX 建设单位") @Schema(description = "建设单位", example = "XX 建设单位")
@@ -64,15 +65,15 @@ public class ProjectSaveReqVO {
@Size(max = 50, message = "工程类型长度不能超过 50 个字符") @Size(max = 50, message = "工程类型长度不能超过 50 个字符")
private String projectType; private String projectType;
@Schema(description = "工程类别", example = "住宅") @Schema(description = "设计类型", example = "住宅")
@Size(max = 50, message = "工程类别长度不能超过 50 个字符") @Size(max = 50, message = "设计类型长度不能超过 50 个字符")
private String projectCategory; private String projectCategory;
@Schema(description = "项目开始年度", requiredMode = Schema.RequiredMode.REQUIRED, example = "2026") @Schema(description = "项目开始年度", requiredMode = Schema.RequiredMode.REQUIRED, example = "2026")
@NotNull(message = "项目开始年度不能为空") @NotNull(message = "项目开始年度不能为空")
private Integer projectStartYear; private Integer projectStartYear;
@Schema(description = "项目状态", example = "进行中") @Schema(description = "项目状态in_progress/completed/paused/terminated", example = "in_progress")
@Size(max = 20, message = "项目状态长度不能超过 20 个字符") @Size(max = 20, message = "项目状态长度不能超过 20 个字符")
private String projectStatus; private String projectStatus;
@@ -84,7 +85,7 @@ public class ProjectSaveReqVO {
@Size(max = 255, message = "中止原因长度不能超过 255 个字符") @Size(max = 255, message = "中止原因长度不能超过 255 个字符")
private String terminateReason; private String terminateReason;
@Schema(description = "最终结算金额", example = "1200000") @Schema(description = "结算合同总产值", example = "1200000")
private BigDecimal finalSettlementAmount; private BigDecimal finalSettlementAmount;
@Schema(description = "科创产值比例", example = "0.0100") @Schema(description = "科创产值比例", example = "0.0100")

View File

@@ -1,12 +1,8 @@
package cn.iocoder.lyzsys.module.tjt.controller.admin.report; package cn.iocoder.lyzsys.module.tjt.controller.admin.report;
import cn.iocoder.lyzsys.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.lyzsys.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.lyzsys.module.tjt.controller.admin.report.vo.EmployeeOutputSummaryExportReqVO; import cn.iocoder.lyzsys.framework.common.pojo.CommonResult;
import cn.iocoder.lyzsys.module.tjt.controller.admin.report.vo.ProjectBudgetExportReqVO; import cn.iocoder.lyzsys.module.tjt.controller.admin.report.vo.*;
import cn.iocoder.lyzsys.module.tjt.controller.admin.report.vo.ProjectLeadQuarterOutputExportReqVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.report.vo.ProjectOverviewExportReqVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.report.vo.ProjectQuarterOutputExportReqVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.report.vo.SpecialtyPersonOutputExportReqVO;
import cn.iocoder.lyzsys.module.tjt.service.report.ProjectOutputReportService; import cn.iocoder.lyzsys.module.tjt.service.report.ProjectOutputReportService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -22,6 +18,7 @@ import javax.validation.Valid;
import java.io.IOException; import java.io.IOException;
import static cn.iocoder.lyzsys.framework.apilog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.lyzsys.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.lyzsys.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 产值报表导出") @Tag(name = "管理后台 - 产值报表导出")
@RestController @RestController
@@ -41,8 +38,16 @@ public class ProjectOutputReportController {
projectOutputReportService.exportProjectBudgetExcel(response, reqVO); projectOutputReportService.exportProjectBudgetExcel(response, reqVO);
} }
@GetMapping("/project-budget/preview")
@Operation(summary = "预览项目考核产值预算表")
@PreAuthorize("@ss.hasAnyPermissions('tjt:report-budget:query', 'tjt:report-budget:export')")
public CommonResult<ProjectBudgetPreviewRespVO> getProjectBudgetPreview(
@Valid ProjectBudgetExportReqVO reqVO) {
return success(projectOutputReportService.getProjectBudgetPreview(reqVO));
}
@GetMapping("/project-quarter-output/export-excel") @GetMapping("/project-quarter-output/export-excel")
@Operation(summary = "导出项目级年度季度计取") @Operation(summary = "导出专业间年度")
@PreAuthorize("@ss.hasPermission('tjt:report-project-quarter:export')") @PreAuthorize("@ss.hasPermission('tjt:report-project-quarter:export')")
@ApiAccessLog(operateType = EXPORT) @ApiAccessLog(operateType = EXPORT)
public void exportProjectQuarterOutputExcel(HttpServletResponse response, public void exportProjectQuarterOutputExcel(HttpServletResponse response,
@@ -50,9 +55,17 @@ public class ProjectOutputReportController {
projectOutputReportService.exportProjectQuarterOutputExcel(response, reqVO); projectOutputReportService.exportProjectQuarterOutputExcel(response, reqVO);
} }
@GetMapping("/project-quarter-output/preview")
@Operation(summary = "预览专业间年度表")
@PreAuthorize("@ss.hasAnyPermissions('tjt:report-project-quarter:query', 'tjt:report-project-quarter:export')")
public CommonResult<ProjectQuarterOutputPreviewRespVO> getProjectQuarterOutputPreview(
@Valid ProjectQuarterOutputExportReqVO reqVO) {
return success(projectOutputReportService.getProjectQuarterOutputPreview(reqVO));
}
@GetMapping("/project-lead-quarter-output/export-excel") @GetMapping("/project-lead-quarter-output/export-excel")
@Operation(summary = "导出工程负责人年度季度计取") @Operation(summary = "导出工程负责人年度表")
@PreAuthorize("@ss.hasPermission('tjt:report-project-quarter:export')") @PreAuthorize("@ss.hasPermission('tjt:report-project-lead-quarter:export')")
@ApiAccessLog(operateType = EXPORT) @ApiAccessLog(operateType = EXPORT)
public void exportProjectLeadQuarterOutputExcel(HttpServletResponse response, public void exportProjectLeadQuarterOutputExcel(HttpServletResponse response,
@Valid ProjectLeadQuarterOutputExportReqVO reqVO) @Valid ProjectLeadQuarterOutputExportReqVO reqVO)
@@ -60,6 +73,14 @@ public class ProjectOutputReportController {
projectOutputReportService.exportProjectLeadQuarterOutputExcel(response, reqVO); projectOutputReportService.exportProjectLeadQuarterOutputExcel(response, reqVO);
} }
@GetMapping("/project-lead-quarter-output/preview")
@Operation(summary = "预览工程负责人年度表")
@PreAuthorize("@ss.hasAnyPermissions('tjt:report-project-lead-quarter:query', 'tjt:report-project-lead-quarter:export')")
public CommonResult<ProjectLeadQuarterOutputPreviewRespVO> getProjectLeadQuarterOutputPreview(
@Valid ProjectLeadQuarterOutputExportReqVO reqVO) {
return success(projectOutputReportService.getProjectLeadQuarterOutputPreview(reqVO));
}
@GetMapping("/specialty-person-output/export-excel") @GetMapping("/specialty-person-output/export-excel")
@Operation(summary = "导出专业内人员年度季度计取表") @Operation(summary = "导出专业内人员年度季度计取表")
@PreAuthorize("@ss.hasPermission('tjt:report-specialty-person:export')") @PreAuthorize("@ss.hasPermission('tjt:report-specialty-person:export')")
@@ -69,6 +90,22 @@ public class ProjectOutputReportController {
projectOutputReportService.exportSpecialtyPersonOutputExcel(response, reqVO); projectOutputReportService.exportSpecialtyPersonOutputExcel(response, reqVO);
} }
@GetMapping("/specialty-person-output/preview")
@Operation(summary = "预览专业内人员年度季度计取表")
@PreAuthorize("@ss.hasAnyPermissions('tjt:report-specialty-person:query', 'tjt:report-specialty-person:export')")
public CommonResult<SpecialtyPersonOutputPreviewRespVO> getSpecialtyPersonOutputPreview(
@Valid SpecialtyPersonOutputPreviewReqVO reqVO) {
return success(projectOutputReportService.getSpecialtyPersonOutputPreview(reqVO));
}
@GetMapping("/project-overview/preview")
@Operation(summary = "预览项目总览表")
@PreAuthorize("@ss.hasAnyPermissions('tjt:report-summary:query', 'tjt:report-summary:export')")
public CommonResult<ProjectOverviewPreviewRespVO> getProjectOverviewPreview(
@Valid ProjectOverviewExportReqVO reqVO) {
return success(projectOutputReportService.getProjectOverviewPreview(reqVO));
}
@GetMapping("/project-overview/export-excel") @GetMapping("/project-overview/export-excel")
@Operation(summary = "导出项目总览表") @Operation(summary = "导出项目总览表")
@PreAuthorize("@ss.hasPermission('tjt:report-summary:export')") @PreAuthorize("@ss.hasPermission('tjt:report-summary:export')")
@@ -78,6 +115,14 @@ public class ProjectOutputReportController {
projectOutputReportService.exportProjectOverviewExcel(response, reqVO); projectOutputReportService.exportProjectOverviewExcel(response, reqVO);
} }
@GetMapping("/employee-output-summary/preview")
@Operation(summary = "预览员工个人考核产值汇总表")
@PreAuthorize("@ss.hasAnyPermissions('tjt:report-summary:query', 'tjt:report-summary:export')")
public CommonResult<EmployeeOutputSummaryPreviewRespVO> getEmployeeOutputSummaryPreview(
@Valid EmployeeOutputSummaryExportReqVO reqVO) {
return success(projectOutputReportService.getEmployeeOutputSummaryPreview(reqVO));
}
@GetMapping("/employee-output-summary/export-excel") @GetMapping("/employee-output-summary/export-excel")
@Operation(summary = "导出员工个人考核产值汇总表") @Operation(summary = "导出员工个人考核产值汇总表")
@PreAuthorize("@ss.hasPermission('tjt:report-summary:export')") @PreAuthorize("@ss.hasPermission('tjt:report-summary:export')")

View File

@@ -15,12 +15,14 @@ public class EmployeeOutputSummaryExcelRespVO {
@ExcelProperty("序号") @ExcelProperty("序号")
private Integer serialNo; private Integer serialNo;
@ExcelProperty("专业所")
private String officeName;
private Integer officeSortNo;
@ExcelProperty("姓名") @ExcelProperty("姓名")
private String employeeName; private String employeeName;
@ExcelProperty("所属专业所")
private String officeName;
@ExcelProperty("第一季度") @ExcelProperty("第一季度")
private BigDecimal quarterOneAmount; private BigDecimal quarterOneAmount;

View File

@@ -0,0 +1,26 @@
package cn.iocoder.lyzsys.module.tjt.controller.admin.report.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
@Schema(description = "管理后台 - 员工个人考核产值汇总表预览 Response VO")
@Data
public class EmployeeOutputSummaryPreviewRespVO {
@Schema(description = "年度", example = "2026")
private Integer year;
@Schema(description = "预计 K 值,小数值,例如 0.4 表示 40%")
private BigDecimal kValue;
@Schema(description = "员工明细行,金额单位:万元")
private List<EmployeeOutputSummaryExcelRespVO> rows = Collections.emptyList();
@Schema(description = "合计行,金额单位:万元")
private EmployeeOutputSummaryExcelRespVO totalRow;
}

View File

@@ -0,0 +1,158 @@
package cn.iocoder.lyzsys.module.tjt.controller.admin.report.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
@Schema(description = "管理后台 - 项目考核产值预算表预览 Response VO")
@Data
public class ProjectBudgetPreviewRespVO {
@Schema(description = "年度", example = "2026")
private Integer year;
@Schema(description = "工程编号")
private String projectCode;
@Schema(description = "项目名称")
private String projectName;
@Schema(description = "备注")
private String remark;
@Schema(description = "建筑(装饰)工程项目考核产值预算表")
private List<BudgetRow> budgetRows = Collections.emptyList();
@Schema(description = "项目考核产值年度季度预算计取表")
private List<QuarterBudgetRow> quarterBudgetRows = Collections.emptyList();
@Schema(description = "建筑(装饰)工程项目考核产值预算表行")
@Data
public static class BudgetRow {
@Schema(description = "行类型")
private String rowType;
@Schema(description = "规划 ID")
private Long planningId;
@Schema(description = "规划内容")
private String planningContent;
@Schema(description = "设计部位")
private String displayDesignPart;
@Schema(description = "设计内容/设计类型")
private String displayBuildingType;
@Schema(description = "内部指导单价")
private BigDecimal internalGuidanceUnitPrice;
@Schema(description = "设计面积")
private BigDecimal designArea;
@Schema(description = "栋数/户型数")
private Integer buildingOrUnitCount;
@Schema(description = "套图系数")
private BigDecimal drawingSetFactor;
@Schema(description = "规模系数")
private BigDecimal scaleFactor;
@Schema(description = "修改系数")
private BigDecimal modificationFactor;
@Schema(description = "复杂系数/复杂等级")
private BigDecimal complexityFactor;
@Schema(description = "小计")
private BigDecimal subtotalArea;
@Schema(description = "设计阶段占比")
private BigDecimal currentDesignStageRatio;
@Schema(description = "考核产值小计,单位:万元")
private BigDecimal assessmentOutputValueWan;
}
@Schema(description = "项目考核产值年度季度预算计取表行")
@Data
public static class QuarterBudgetRow {
@Schema(description = "序号")
private Integer serialNo;
@Schema(description = "是否合计行")
private Boolean totalRow = false;
@Schema(description = "产值类型")
private String outputType;
@Schema(description = "设计内容")
private String designContent;
@Schema(description = "预算年度")
private Integer budgetYear;
@Schema(description = "总建筑(精装)设计面积")
private BigDecimal totalDesignArea;
@Schema(description = "总考核产值面积")
private BigDecimal totalAssessmentArea;
@Schema(description = "总考核产值,单位:万元")
private BigDecimal totalAssessmentOutputWan;
@Schema(description = "阶段占比")
private BigDecimal designStageRatio;
@Schema(description = "设计阶段考核产值,单位:万元")
private BigDecimal designStageOutputWan;
@Schema(description = "往年已发放比例")
private BigDecimal historicalIssuedRatio;
@Schema(description = "一季度发放比例")
private BigDecimal quarterOneRatio;
@Schema(description = "二季度发放比例")
private BigDecimal quarterTwoRatio;
@Schema(description = "三季度发放比例")
private BigDecimal quarterThreeRatio;
@Schema(description = "四季度发放比例")
private BigDecimal quarterFourRatio;
@Schema(description = "本年度小计比例")
private BigDecimal currentYearRatio;
@Schema(description = "未发放比例")
private BigDecimal pendingRatio;
@Schema(description = "一季度金额,单位:万元")
private BigDecimal quarterOneAmountWan;
@Schema(description = "二季度金额,单位:万元")
private BigDecimal quarterTwoAmountWan;
@Schema(description = "三季度金额,单位:万元")
private BigDecimal quarterThreeAmountWan;
@Schema(description = "四季度金额,单位:万元")
private BigDecimal quarterFourAmountWan;
@Schema(description = "本年度小计金额,单位:万元")
private BigDecimal yearTotalAmountWan;
@Schema(description = "备注")
private String ratioRemark;
}
}

View File

@@ -5,13 +5,13 @@ import lombok.Data;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
@Schema(description = "管理后台 - 工程负责人年度季度计取表导出 Request VO") @Schema(description = "管理后台 - 工程负责人年度表导出 Request VO")
@Data @Data
public class ProjectLeadQuarterOutputExportReqVO { public class ProjectLeadQuarterOutputExportReqVO {
@Schema(description = "合约规划 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @Schema(description = "项目 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "合约规划 ID 不能为空") @NotNull(message = "项目 ID 不能为空")
private Long planningId; private Long projectId;
@Schema(description = "导出年度", example = "2026") @Schema(description = "导出年度", example = "2026")
private Integer year; private Integer year;

View File

@@ -0,0 +1,89 @@
package cn.iocoder.lyzsys.module.tjt.controller.admin.report.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
@Schema(description = "管理后台 - 工程负责人年度表预览 Response VO")
@Data
public class ProjectLeadQuarterOutputPreviewRespVO {
@Schema(description = "项目名称")
private String projectName;
@Schema(description = "预览年度")
private Integer year;
@Schema(description = "项目经理人员名称,多个使用 / 分隔")
private String projectManagerNames;
@Schema(description = "工程负责人人员名称,多个使用 / 分隔")
private String engineeringPrincipalNames;
@Schema(description = "预览行")
private List<LeadQuarterRow> rows = Collections.emptyList();
@Schema(description = "工程负责人年度表预览行")
@Data
public static class LeadQuarterRow {
@Schema(description = "序号")
private Integer serialNo;
@Schema(description = "产值类型")
private String outputType;
@Schema(description = "设计内容")
private String designContent;
@Schema(description = "是否小计行")
private Boolean subtotalRow;
@Schema(description = "项目经理人员名称")
private String projectManagerNames;
@Schema(description = "项目经理工作比例")
private BigDecimal projectManagerRatio;
@Schema(description = "工程负责人人员名称")
private String engineeringPrincipalNames;
@Schema(description = "工程负责人工作比例")
private BigDecimal engineeringPrincipalRatio;
@Schema(description = "项目经理一季度金额,万元")
private BigDecimal projectManagerQuarterOneAmountWan;
@Schema(description = "项目经理二季度金额,万元")
private BigDecimal projectManagerQuarterTwoAmountWan;
@Schema(description = "项目经理三季度金额,万元")
private BigDecimal projectManagerQuarterThreeAmountWan;
@Schema(description = "项目经理四季度金额,万元")
private BigDecimal projectManagerQuarterFourAmountWan;
@Schema(description = "项目经理本年度小计,万元")
private BigDecimal projectManagerYearTotalAmountWan;
@Schema(description = "工程负责人一季度金额,万元")
private BigDecimal engineeringPrincipalQuarterOneAmountWan;
@Schema(description = "工程负责人二季度金额,万元")
private BigDecimal engineeringPrincipalQuarterTwoAmountWan;
@Schema(description = "工程负责人三季度金额,万元")
private BigDecimal engineeringPrincipalQuarterThreeAmountWan;
@Schema(description = "工程负责人四季度金额,万元")
private BigDecimal engineeringPrincipalQuarterFourAmountWan;
@Schema(description = "工程负责人本年度小计,万元")
private BigDecimal engineeringPrincipalYearTotalAmountWan;
}
}

View File

@@ -0,0 +1,103 @@
package cn.iocoder.lyzsys.module.tjt.controller.admin.report.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@Schema(description = "管理后台 - 项目总览表预览 Response VO")
@Data
public class ProjectOverviewPreviewRespVO {
@Schema(description = "年度", example = "2026")
private Integer year;
@Schema(description = "专业所名称", example = "给排水所")
private String officeName;
@Schema(description = "员工动态列")
private List<EmployeeColumn> employeeColumns = Collections.emptyList();
@Schema(description = "项目行")
private List<ProjectRow> rows = Collections.emptyList();
@Schema(description = "合计行")
private ProjectRow totalRow;
@Schema(description = "员工动态列")
@Data
public static class EmployeeColumn {
@Schema(description = "员工 ID", example = "1")
private Long employeeId;
@Schema(description = "员工姓名", example = "张三")
private String employeeName;
}
@Schema(description = "项目总览行")
@Data
public static class ProjectRow {
@Schema(description = "序号", example = "1")
private Integer serialNo;
@Schema(description = "是否合计行", example = "false")
private Boolean totalRow = false;
@Schema(description = "项目名称")
private String projectName;
@Schema(description = "工程进度情况及其它说明")
private String progressText;
@Schema(description = "工作阶段")
private String workStage;
@Schema(description = "本专业 + 项目总核算总产值,单位:万元")
private BigDecimal totalOutputAmountWan;
@Schema(description = "往期已发放比例,小数值,例如 0.2 表示 20%")
private BigDecimal historicalIssuedRatio;
@Schema(description = "本期结算占比,小数值,例如 0.2 表示 20%")
private BigDecimal currentSettlementRatio;
@Schema(description = "本期结算考核产值,单位:万元")
private BigDecimal currentSettlementAmountWan;
@Schema(description = "未结算比例,小数值,例如 0.2 表示 20%")
private BigDecimal pendingRatio;
@Schema(description = "员工季度金额key 为员工 ID金额单位万元")
private Map<Long, EmployeeAmountValue> employeeAmountMap = new LinkedHashMap<>();
}
@Schema(description = "员工季度金额")
@Data
public static class EmployeeAmountValue {
@Schema(description = "一季度,单位:万元")
private BigDecimal quarterOneAmountWan;
@Schema(description = "二季度,单位:万元")
private BigDecimal quarterTwoAmountWan;
@Schema(description = "三季度,单位:万元")
private BigDecimal quarterThreeAmountWan;
@Schema(description = "四季度,单位:万元")
private BigDecimal quarterFourAmountWan;
@Schema(description = "本年度小计,单位:万元")
private BigDecimal annualTotalAmountWan;
}
}

View File

@@ -5,13 +5,13 @@ import lombok.Data;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
@Schema(description = "管理后台 - 项目级年度季度计取表导出 Request VO") @Schema(description = "管理后台 - 专业间年度表导出 Request VO")
@Data @Data
public class ProjectQuarterOutputExportReqVO { public class ProjectQuarterOutputExportReqVO {
@Schema(description = "合约规划 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @Schema(description = "项目 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "合约规划 ID 不能为空") @NotNull(message = "项目 ID 不能为空")
private Long planningId; private Long projectId;
@Schema(description = "导出年度", example = "2026") @Schema(description = "导出年度", example = "2026")
private Integer year; private Integer year;

View File

@@ -0,0 +1,146 @@
package cn.iocoder.lyzsys.module.tjt.controller.admin.report.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
@Schema(description = "管理后台 - 专业间年度表预览 Response VO")
@Data
public class ProjectQuarterOutputPreviewRespVO {
@Schema(description = "工程编号")
private String projectCode;
@Schema(description = "项目名称")
private String projectName;
@Schema(description = "预览年度")
private Integer year;
@Schema(description = "预览行")
private List<QuarterRow> rows = Collections.emptyList();
@Schema(description = "专业间年度表预览行")
@Data
public static class QuarterRow {
@Schema(description = "序号")
private Integer serialNo;
@Schema(description = "是否合计行")
private Boolean totalRow;
@Schema(description = "是否占位行")
private Boolean placeholderRow;
@Schema(description = "产值类型")
private String outputType;
@Schema(description = "设计内容")
private String designContent;
@Schema(description = "一季度金额,万元")
private BigDecimal quarterOneAmountWan;
@Schema(description = "二季度金额,万元")
private BigDecimal quarterTwoAmountWan;
@Schema(description = "三季度金额,万元")
private BigDecimal quarterThreeAmountWan;
@Schema(description = "四季度金额,万元")
private BigDecimal quarterFourAmountWan;
@Schema(description = "本年度小计,万元")
private BigDecimal yearTotalAmountWan;
@Schema(description = "项目经理/工程负责人占比")
private BigDecimal projectLeadRatio;
@Schema(description = "项目经理/工程负责人总考核产值,万元")
private BigDecimal projectLeadAssessmentOutputWan;
@Schema(description = "项目经理/工程负责人一季度金额,万元")
private BigDecimal projectLeadQuarterOneAmountWan;
@Schema(description = "项目经理/工程负责人二季度金额,万元")
private BigDecimal projectLeadQuarterTwoAmountWan;
@Schema(description = "项目经理/工程负责人三季度金额,万元")
private BigDecimal projectLeadQuarterThreeAmountWan;
@Schema(description = "项目经理/工程负责人四季度金额,万元")
private BigDecimal projectLeadQuarterFourAmountWan;
@Schema(description = "项目经理/工程负责人本年度总计,万元")
private BigDecimal projectLeadYearTotalAmountWan;
@Schema(description = "专业所占比")
private BigDecimal officeRatio;
@Schema(description = "专业所总考核产值,万元")
private BigDecimal officeAssessmentOutputWan;
@Schema(description = "专业所一季度金额,万元")
private BigDecimal officeQuarterOneAmountWan;
@Schema(description = "专业所二季度金额,万元")
private BigDecimal officeQuarterTwoAmountWan;
@Schema(description = "专业所三季度金额,万元")
private BigDecimal officeQuarterThreeAmountWan;
@Schema(description = "专业所四季度金额,万元")
private BigDecimal officeQuarterFourAmountWan;
@Schema(description = "专业所本年度总计,万元")
private BigDecimal officeYearTotalAmountWan;
@Schema(description = "建筑专业占比")
private BigDecimal archRatio;
@Schema(description = "精装专业占比")
private BigDecimal decorRatio;
@Schema(description = "结构专业占比")
private BigDecimal structRatio;
@Schema(description = "给排水专业占比")
private BigDecimal waterRatio;
@Schema(description = "暖通专业占比")
private BigDecimal hvacRatio;
@Schema(description = "电气专业占比")
private BigDecimal elecRatio;
@Schema(description = "数字化设计专业占比")
private BigDecimal digitalRatio;
@Schema(description = "建筑专业考核产值,万元")
private BigDecimal archAssessmentOutputWan;
@Schema(description = "精装专业考核产值,万元")
private BigDecimal decorAssessmentOutputWan;
@Schema(description = "结构专业考核产值,万元")
private BigDecimal structAssessmentOutputWan;
@Schema(description = "给排水专业考核产值,万元")
private BigDecimal waterAssessmentOutputWan;
@Schema(description = "暖通专业考核产值,万元")
private BigDecimal hvacAssessmentOutputWan;
@Schema(description = "电气专业考核产值,万元")
private BigDecimal elecAssessmentOutputWan;
@Schema(description = "数字化设计专业考核产值,万元")
private BigDecimal digitalAssessmentOutputWan;
}
}

View File

@@ -0,0 +1,19 @@
package cn.iocoder.lyzsys.module.tjt.controller.admin.report.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Schema(description = "管理后台 - 专业内人员年度季度计取预览 Request VO")
@Data
public class SpecialtyPersonOutputPreviewReqVO {
@Schema(description = "合约规划 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "合约规划 ID 不能为空")
private Long planningId;
@Schema(description = "预览年度", example = "2026")
private Integer year;
}

View File

@@ -0,0 +1,157 @@
package cn.iocoder.lyzsys.module.tjt.controller.admin.report.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
@Schema(description = "管理后台 - 专业内人员年度季度计取预览 Response VO")
@Data
public class SpecialtyPersonOutputPreviewRespVO {
@Schema(description = "锚点合约规划 ID")
private Long planningId;
@Schema(description = "预览年度")
private Integer year;
@Schema(description = "项目名称")
private String projectName;
@Schema(description = "专业分组")
private List<GroupRow> groups;
@Schema(description = "专业分组")
@Data
public static class GroupRow {
@Schema(description = "专业编码")
private String specialtyCode;
@Schema(description = "专业名称")
private String specialtyName;
@Schema(description = "是否允许导出专业内人员计取表")
private Boolean exportable;
@Schema(description = "专业金额(元)")
private BigDecimal specialtyAmount;
@Schema(description = "角色比例合计")
private BigDecimal roleTotal;
@Schema(description = "已配置人数")
private Integer personCount;
@Schema(description = "是否超额")
private Boolean overRatio;
@Schema(description = "专业一季度金额(万元)")
private BigDecimal specialtyQuarterOneAmountWan;
@Schema(description = "专业二季度金额(万元)")
private BigDecimal specialtyQuarterTwoAmountWan;
@Schema(description = "专业三季度金额(万元)")
private BigDecimal specialtyQuarterThreeAmountWan;
@Schema(description = "专业四季度金额(万元)")
private BigDecimal specialtyQuarterFourAmountWan;
@Schema(description = "专业本年度小计金额(万元)")
private BigDecimal specialtyYearTotalAmountWan;
@Schema(description = "角色人员年度季度计取明细")
private List<RoleRow> rows;
}
@Schema(description = "角色人员年度季度计取明细")
@Data
public static class RoleRow {
@Schema(description = "专业编码")
private String specialtyCode;
@Schema(description = "专业名称")
private String specialtyName;
@Schema(description = "角色编码")
private String roleCode;
@Schema(description = "角色名称")
private String roleName;
@Schema(description = "角色比例")
private BigDecimal roleRatio;
@Schema(description = "角色金额(元)")
private BigDecimal roleAmount;
@Schema(description = "人员比例合计")
private BigDecimal personTotalRatio;
@Schema(description = "人员明细")
private List<PersonRow> persons;
}
@Schema(description = "人员年度季度计取明细")
@Data
public static class PersonRow {
@Schema(description = "人员唯一键")
private String personKey;
@Schema(description = "员工 ID")
private Long employeeId;
@Schema(description = "员工姓名")
private String employeeName;
@Schema(description = "人员工作量比例")
private BigDecimal personRatio;
@Schema(description = "人员金额(元)")
private BigDecimal personAmount;
@Schema(description = "参与角色")
private String roleNames;
@Schema(description = "占专业比例合计")
private BigDecimal adjustedPersonRatio;
@Schema(description = "一季度比例")
private BigDecimal quarterOneRatio;
@Schema(description = "一季度金额(万元)")
private BigDecimal quarterOneAmountWan;
@Schema(description = "二季度比例")
private BigDecimal quarterTwoRatio;
@Schema(description = "二季度金额(万元)")
private BigDecimal quarterTwoAmountWan;
@Schema(description = "三季度比例")
private BigDecimal quarterThreeRatio;
@Schema(description = "三季度金额(万元)")
private BigDecimal quarterThreeAmountWan;
@Schema(description = "四季度比例")
private BigDecimal quarterFourRatio;
@Schema(description = "四季度金额(万元)")
private BigDecimal quarterFourAmountWan;
@Schema(description = "本年度小计比例")
private BigDecimal yearTotalRatio;
@Schema(description = "本年度小计金额(万元)")
private BigDecimal yearTotalAmountWan;
}
}

View File

@@ -21,4 +21,7 @@ public class SpecialtyRoleSplitBatchSaveReqVO {
@Valid @Valid
private List<SpecialtyRoleSplitSaveItemReqVO> items; private List<SpecialtyRoleSplitSaveItemReqVO> items;
@Schema(description = "是否临时保存。true 时仅做基础格式处理,跳过角色合计、设计人员必填等强校验", example = "false")
private Boolean temporarySave;
} }

View File

@@ -38,6 +38,8 @@ public class EmployeeDO extends TenantBaseDO {
private String remark; private String remark;
private Boolean officeLeaderFlag;
private Integer sortNo; private Integer sortNo;
private Boolean enabledFlag; private Boolean enabledFlag;

View File

@@ -0,0 +1,35 @@
package cn.iocoder.lyzsys.module.tjt.dal.dataobject.employeeyearleaderoutput;
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;
@TableName("tjt_employee_year_leader_output")
@KeySequence("tjt_employee_year_leader_output_seq")
@Data
@EqualsAndHashCode(callSuper = true)
public class EmployeeYearLeaderOutputDO extends TenantBaseDO {
@TableId
private Long id;
private Long employeeId;
private String employeeName;
private Integer outputYear;
private BigDecimal leaderOutputAmount;
private String remark;
private Integer sortNo;
private Boolean enabledFlag;
}

View File

@@ -25,7 +25,7 @@ public class ProjectPlanningDO extends TenantBaseDO {
private Long projectId; private Long projectId;
private Integer sortNo; private String sortNo;
private String ownershipType; private String ownershipType;

View File

@@ -25,6 +25,10 @@ public class ProjectPlanningQuarterDO extends TenantBaseDO {
private Long planningId; private Long planningId;
private Long guideDetailId;
private Integer guideDetailSortNo;
private Integer distributionYear; private Integer distributionYear;
private Integer quarterNo; private Integer quarterNo;

View File

@@ -0,0 +1,83 @@
package cn.iocoder.lyzsys.module.tjt.dal.dataobject.profit;
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.LocalDateTime;
/**
* 项目成本测算快照 DO
*
* @author Codex
*/
@TableName("tjt_project_cost_measure_snapshot")
@KeySequence("tjt_project_cost_measure_snapshot_seq")
@Data
@EqualsAndHashCode(callSuper = true)
public class ProjectCostMeasureSnapshotDO extends TenantBaseDO {
@TableId
private Long id;
private Long projectId;
private String snapshotType;
private Boolean lockedFlag;
private Long actionUserId;
private String actionUserName;
private LocalDateTime actionTime;
private BigDecimal contractAmount;
private BigDecimal finalSettlementAmount;
private BigDecimal effectiveSettlementAmount;
private BigDecimal comprehensivePlanningAmount;
private BigDecimal subcontractPlanningAmount;
private BigDecimal specialSubcontractPlanningAmount;
private BigDecimal sourceCoopSubcontractPlanningAmount;
private BigDecimal comprehensiveSubcontractPlanningAmount;
private BigDecimal majorOutputValue;
private BigDecimal majorExpectedPerformance;
private BigDecimal innovationOutputRate;
private BigDecimal innovationOutputValue;
private BigDecimal otherCost;
private BigDecimal profitLossValue;
private BigDecimal profitLossRate;
private String assessmentResult;
private BigDecimal assessmentCoefficient;
private BigDecimal comprehensiveAccountingOutputValue;
private BigDecimal comprehensiveSettlementOutputValue;
private BigDecimal majorAccountingOutputValue;
private BigDecimal majorSettlementOutputValue;
private String remark;
}

View File

@@ -34,17 +34,17 @@ public class ProjectDO extends TenantBaseDO {
/** /**
* 排序 * 排序
*/ */
private Integer sortNo; private String sortNo;
/** /**
* 是否签订合同 * 是否签订合同
*/ */
private Boolean contractSignedFlag; private Boolean contractSignedFlag;
/** /**
* 合同产值 * 合同产值
*/ */
private BigDecimal contractAmount; private BigDecimal contractAmount;
/** /**
* 工程总面积 * 建筑面积
*/ */
private BigDecimal totalConstructionArea; private BigDecimal totalConstructionArea;
/** /**
@@ -68,7 +68,7 @@ public class ProjectDO extends TenantBaseDO {
*/ */
private String projectType; private String projectType;
/** /**
* 工程类别 * 设计类型
*/ */
private String projectCategory; private String projectCategory;
/** /**
@@ -96,7 +96,7 @@ public class ProjectDO extends TenantBaseDO {
*/ */
private String terminateReason; private String terminateReason;
/** /**
* 最终结算金额 * 结算合同总产值
*/ */
private BigDecimal finalSettlementAmount; private BigDecimal finalSettlementAmount;
/** /**

View File

@@ -35,8 +35,6 @@ public class SpecialtyRoleSplitDO extends TenantBaseDO {
private BigDecimal roleRatio; private BigDecimal roleRatio;
private String personsJson;
private Integer sortNo; private Integer sortNo;
} }

View File

@@ -0,0 +1,50 @@
package cn.iocoder.lyzsys.module.tjt.dal.dataobject.specialtyrolesplitperson;
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_person")
@KeySequence("tjt_specialty_role_split_person_seq")
@Data
@EqualsAndHashCode(callSuper = true)
public class SpecialtyRoleSplitPersonDO extends TenantBaseDO {
@TableId
private Long id;
private Long roleSplitId;
private Long outputSplitId;
private Long projectId;
private Long planningId;
private String specialtyCode;
private String specialtyName;
private String roleCode;
private String roleName;
private Long employeeId;
private String employeeName;
private BigDecimal personRatio;
private Integer sortNo;
}

View File

@@ -18,16 +18,34 @@ public interface EmployeeMapper extends BaseMapperX<EmployeeDO> {
.eqIfPresent(EmployeeDO::getOfficeId, reqVO.getOfficeId()) .eqIfPresent(EmployeeDO::getOfficeId, reqVO.getOfficeId())
.eqIfPresent(EmployeeDO::getEmployeeStatus, reqVO.getEmployeeStatus()) .eqIfPresent(EmployeeDO::getEmployeeStatus, reqVO.getEmployeeStatus())
.eqIfPresent(EmployeeDO::getEnabledFlag, reqVO.getEnabledFlag()) .eqIfPresent(EmployeeDO::getEnabledFlag, reqVO.getEnabledFlag())
.eqIfPresent(EmployeeDO::getOfficeLeaderFlag, reqVO.getOfficeLeaderFlag())
.orderByAsc(EmployeeDO::getSortNo) .orderByAsc(EmployeeDO::getSortNo)
.orderByAsc(EmployeeDO::getId)); .orderByAsc(EmployeeDO::getId));
} }
default List<EmployeeDO> selectSimpleList(String keyword, Long officeId, String status, Boolean enabledFlag) { default List<EmployeeDO> selectSimpleList(String keyword, Long officeId, String status, Boolean enabledFlag,
Boolean officeLeaderFlag) {
return selectList(new LambdaQueryWrapperX<EmployeeDO>() return selectList(new LambdaQueryWrapperX<EmployeeDO>()
.likeIfPresent(EmployeeDO::getEmployeeName, keyword) .likeIfPresent(EmployeeDO::getEmployeeName, keyword)
.eqIfPresent(EmployeeDO::getOfficeId, officeId) .eqIfPresent(EmployeeDO::getOfficeId, officeId)
.eqIfPresent(EmployeeDO::getEmployeeStatus, status) .eqIfPresent(EmployeeDO::getEmployeeStatus, status)
.eqIfPresent(EmployeeDO::getEnabledFlag, enabledFlag) .eqIfPresent(EmployeeDO::getEnabledFlag, enabledFlag)
.eqIfPresent(EmployeeDO::getOfficeLeaderFlag, officeLeaderFlag)
.orderByAsc(EmployeeDO::getSortNo)
.orderByAsc(EmployeeDO::getId));
}
default List<EmployeeDO> selectEnabledList() {
return selectList(new LambdaQueryWrapperX<EmployeeDO>()
.eq(EmployeeDO::getEnabledFlag, Boolean.TRUE)
.orderByAsc(EmployeeDO::getSortNo)
.orderByAsc(EmployeeDO::getId));
}
default List<EmployeeDO> selectEnabledLeaderList() {
return selectList(new LambdaQueryWrapperX<EmployeeDO>()
.eq(EmployeeDO::getEnabledFlag, Boolean.TRUE)
.eq(EmployeeDO::getOfficeLeaderFlag, Boolean.TRUE)
.orderByAsc(EmployeeDO::getSortNo) .orderByAsc(EmployeeDO::getSortNo)
.orderByAsc(EmployeeDO::getId)); .orderByAsc(EmployeeDO::getId));
} }

View File

@@ -7,6 +7,8 @@ import cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearcostbudget.vo.E
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.employeeyearcostbudget.EmployeeYearCostBudgetDO; import cn.iocoder.lyzsys.module.tjt.dal.dataobject.employeeyearcostbudget.EmployeeYearCostBudgetDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper @Mapper
public interface EmployeeYearCostBudgetMapper extends BaseMapperX<EmployeeYearCostBudgetDO> { public interface EmployeeYearCostBudgetMapper extends BaseMapperX<EmployeeYearCostBudgetDO> {
@@ -27,6 +29,11 @@ public interface EmployeeYearCostBudgetMapper extends BaseMapperX<EmployeeYearCo
.eq(EmployeeYearCostBudgetDO::getBudgetYear, budgetYear)); .eq(EmployeeYearCostBudgetDO::getBudgetYear, budgetYear));
} }
default List<EmployeeYearCostBudgetDO> selectListByBudgetYear(Integer budgetYear) {
return selectList(new LambdaQueryWrapperX<EmployeeYearCostBudgetDO>()
.eq(EmployeeYearCostBudgetDO::getBudgetYear, budgetYear));
}
default Long selectCountByEmployeeId(Long employeeId) { default Long selectCountByEmployeeId(Long employeeId) {
return selectCount(new LambdaQueryWrapperX<EmployeeYearCostBudgetDO>() return selectCount(new LambdaQueryWrapperX<EmployeeYearCostBudgetDO>()
.eq(EmployeeYearCostBudgetDO::getEmployeeId, employeeId)); .eq(EmployeeYearCostBudgetDO::getEmployeeId, employeeId));

View File

@@ -0,0 +1,53 @@
package cn.iocoder.lyzsys.module.tjt.dal.mysql.employeeyearleaderoutput;
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.employeeyearleaderoutput.vo.EmployeeYearLeaderOutputPageReqVO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.employeeyearleaderoutput.EmployeeYearLeaderOutputDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
import java.util.List;
@Mapper
public interface EmployeeYearLeaderOutputMapper extends BaseMapperX<EmployeeYearLeaderOutputDO> {
default PageResult<EmployeeYearLeaderOutputDO> selectPage(EmployeeYearLeaderOutputPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<EmployeeYearLeaderOutputDO>()
.eqIfPresent(EmployeeYearLeaderOutputDO::getEmployeeId, reqVO.getEmployeeId())
.likeIfPresent(EmployeeYearLeaderOutputDO::getEmployeeName, reqVO.getEmployeeName())
.eqIfPresent(EmployeeYearLeaderOutputDO::getOutputYear, reqVO.getOutputYear())
.eqIfPresent(EmployeeYearLeaderOutputDO::getEnabledFlag, reqVO.getEnabledFlag())
.orderByDesc(EmployeeYearLeaderOutputDO::getOutputYear)
.orderByAsc(EmployeeYearLeaderOutputDO::getSortNo)
.orderByAsc(EmployeeYearLeaderOutputDO::getId));
}
default EmployeeYearLeaderOutputDO selectByEmployeeIdAndOutputYear(Long employeeId, Integer outputYear) {
return selectOne(new LambdaQueryWrapperX<EmployeeYearLeaderOutputDO>()
.eq(EmployeeYearLeaderOutputDO::getEmployeeId, employeeId)
.eq(EmployeeYearLeaderOutputDO::getOutputYear, outputYear));
}
default List<EmployeeYearLeaderOutputDO> selectListByOutputYear(Integer outputYear) {
return selectList(new LambdaQueryWrapperX<EmployeeYearLeaderOutputDO>()
.eq(EmployeeYearLeaderOutputDO::getOutputYear, outputYear));
}
default List<EmployeeYearLeaderOutputDO> selectEnabledListByOutputYear(Integer outputYear,
Collection<Long> employeeIds) {
return selectList(new LambdaQueryWrapperX<EmployeeYearLeaderOutputDO>()
.eq(EmployeeYearLeaderOutputDO::getOutputYear, outputYear)
.eq(EmployeeYearLeaderOutputDO::getEnabledFlag, Boolean.TRUE)
.inIfPresent(EmployeeYearLeaderOutputDO::getEmployeeId, employeeIds)
.orderByAsc(EmployeeYearLeaderOutputDO::getSortNo)
.orderByAsc(EmployeeYearLeaderOutputDO::getId));
}
default Long selectCountByEmployeeId(Long employeeId) {
return selectCount(new LambdaQueryWrapperX<EmployeeYearLeaderOutputDO>()
.eq(EmployeeYearLeaderOutputDO::getEmployeeId, employeeId));
}
}

View File

@@ -25,8 +25,7 @@ public interface ProjectPlanningMapper extends BaseMapperX<ProjectPlanningDO> {
.likeIfPresent(ProjectPlanningDO::getPlanningContent, reqVO.getPlanningContent()) .likeIfPresent(ProjectPlanningDO::getPlanningContent, reqVO.getPlanningContent())
.eqIfPresent(ProjectPlanningDO::getPlanningStartYear, reqVO.getPlanningStartYear()) .eqIfPresent(ProjectPlanningDO::getPlanningStartYear, reqVO.getPlanningStartYear())
.betweenIfPresent(ProjectPlanningDO::getCreateTime, reqVO.getCreateTime()) .betweenIfPresent(ProjectPlanningDO::getCreateTime, reqVO.getCreateTime())
.orderByAsc(ProjectPlanningDO::getSortNo) .last("ORDER BY CASE WHEN sort_no IS NULL OR sort_no = N'' THEN 1 ELSE 0 END, sort_no ASC, id ASC"));
.orderByAsc(ProjectPlanningDO::getId));
} }
default List<ProjectPlanningDO> selectListByProjectId(Long projectId) { default List<ProjectPlanningDO> selectListByProjectId(Long projectId) {
@@ -38,8 +37,7 @@ public interface ProjectPlanningMapper extends BaseMapperX<ProjectPlanningDO> {
default List<ProjectPlanningDO> selectDisplayListByProjectId(Long projectId) { default List<ProjectPlanningDO> selectDisplayListByProjectId(Long projectId) {
return selectList(new LambdaQueryWrapperX<ProjectPlanningDO>() return selectList(new LambdaQueryWrapperX<ProjectPlanningDO>()
.eq(ProjectPlanningDO::getProjectId, projectId) .eq(ProjectPlanningDO::getProjectId, projectId)
.orderByAsc(ProjectPlanningDO::getSortNo) .last("ORDER BY CASE WHEN sort_no IS NULL OR sort_no = N'' THEN 1 ELSE 0 END, sort_no ASC, id ASC"));
.orderByAsc(ProjectPlanningDO::getId));
} }
} }

View File

@@ -20,25 +20,102 @@ public interface ProjectPlanningQuarterMapper extends BaseMapperX<ProjectPlannin
default ProjectPlanningQuarterDO selectByPlanningIdAndDistributionYearAndQuarter(Long planningId, default ProjectPlanningQuarterDO selectByPlanningIdAndDistributionYearAndQuarter(Long planningId,
Integer distributionYear, Integer distributionYear,
Integer quarterNo) { Integer quarterNo) {
return selectOne(ProjectPlanningQuarterDO::getPlanningId, planningId, return selectParentByPlanningIdAndDistributionYearAndQuarter(planningId, distributionYear, quarterNo);
ProjectPlanningQuarterDO::getDistributionYear, distributionYear, }
ProjectPlanningQuarterDO::getQuarterNo, quarterNo);
default ProjectPlanningQuarterDO selectParentByPlanningIdAndDistributionYearAndQuarter(Long planningId,
Integer distributionYear,
Integer quarterNo) {
return selectOne(new LambdaQueryWrapperX<ProjectPlanningQuarterDO>()
.eq(ProjectPlanningQuarterDO::getPlanningId, planningId)
.eq(ProjectPlanningQuarterDO::getDistributionYear, distributionYear)
.eq(ProjectPlanningQuarterDO::getQuarterNo, quarterNo)
.isNull(ProjectPlanningQuarterDO::getGuideDetailId));
}
default ProjectPlanningQuarterDO selectByPlanningIdAndGuideDetailIdAndDistributionYearAndQuarter(
Long planningId, Long guideDetailId, Integer distributionYear, Integer quarterNo) {
return selectOne(new LambdaQueryWrapperX<ProjectPlanningQuarterDO>()
.eq(ProjectPlanningQuarterDO::getPlanningId, planningId)
.eq(ProjectPlanningQuarterDO::getGuideDetailId, guideDetailId)
.eq(ProjectPlanningQuarterDO::getDistributionYear, distributionYear)
.eq(ProjectPlanningQuarterDO::getQuarterNo, quarterNo));
} }
default List<ProjectPlanningQuarterDO> selectListByPlanningId(Long planningId) { default List<ProjectPlanningQuarterDO> selectListByPlanningId(Long planningId) {
return selectList(new LambdaQueryWrapperX<ProjectPlanningQuarterDO>() return selectList(new LambdaQueryWrapperX<ProjectPlanningQuarterDO>()
.eq(ProjectPlanningQuarterDO::getPlanningId, planningId) .eq(ProjectPlanningQuarterDO::getPlanningId, planningId)
.orderByAsc(ProjectPlanningQuarterDO::getGuideDetailSortNo)
.orderByAsc(ProjectPlanningQuarterDO::getGuideDetailId)
.orderByAsc(ProjectPlanningQuarterDO::getDistributionYear) .orderByAsc(ProjectPlanningQuarterDO::getDistributionYear)
.orderByAsc(ProjectPlanningQuarterDO::getQuarterNo) .orderByAsc(ProjectPlanningQuarterDO::getQuarterNo)
.orderByAsc(ProjectPlanningQuarterDO::getId)); .orderByAsc(ProjectPlanningQuarterDO::getId));
} }
default List<ProjectPlanningQuarterDO> selectParentListByPlanningId(Long planningId) {
return selectList(new LambdaQueryWrapperX<ProjectPlanningQuarterDO>()
.eq(ProjectPlanningQuarterDO::getPlanningId, planningId)
.isNull(ProjectPlanningQuarterDO::getGuideDetailId)
.orderByAsc(ProjectPlanningQuarterDO::getDistributionYear)
.orderByAsc(ProjectPlanningQuarterDO::getQuarterNo)
.orderByAsc(ProjectPlanningQuarterDO::getId));
}
default List<ProjectPlanningQuarterDO> selectDetailListByPlanningId(Long planningId) {
return selectList(new LambdaQueryWrapperX<ProjectPlanningQuarterDO>()
.eq(ProjectPlanningQuarterDO::getPlanningId, planningId)
.isNotNull(ProjectPlanningQuarterDO::getGuideDetailId)
.orderByAsc(ProjectPlanningQuarterDO::getGuideDetailSortNo)
.orderByAsc(ProjectPlanningQuarterDO::getGuideDetailId)
.orderByAsc(ProjectPlanningQuarterDO::getDistributionYear)
.orderByAsc(ProjectPlanningQuarterDO::getQuarterNo)
.orderByAsc(ProjectPlanningQuarterDO::getId));
}
default List<ProjectPlanningQuarterDO> selectListByGuideDetailId(Long guideDetailId) {
return selectList(new LambdaQueryWrapperX<ProjectPlanningQuarterDO>()
.eq(ProjectPlanningQuarterDO::getGuideDetailId, guideDetailId)
.orderByAsc(ProjectPlanningQuarterDO::getDistributionYear)
.orderByAsc(ProjectPlanningQuarterDO::getQuarterNo)
.orderByAsc(ProjectPlanningQuarterDO::getId));
}
default List<ProjectPlanningQuarterDO> selectListByGuideDetailIds(Collection<Long> guideDetailIds) {
if (guideDetailIds == null || guideDetailIds.isEmpty()) {
return Collections.emptyList();
}
return selectList(new LambdaQueryWrapperX<ProjectPlanningQuarterDO>()
.in(ProjectPlanningQuarterDO::getGuideDetailId, guideDetailIds)
.orderByAsc(ProjectPlanningQuarterDO::getGuideDetailSortNo)
.orderByAsc(ProjectPlanningQuarterDO::getGuideDetailId)
.orderByAsc(ProjectPlanningQuarterDO::getDistributionYear)
.orderByAsc(ProjectPlanningQuarterDO::getQuarterNo)
.orderByAsc(ProjectPlanningQuarterDO::getId));
}
default boolean existsParentQuarter(Long planningId, Long excludeId) {
return selectCount(new LambdaQueryWrapperX<ProjectPlanningQuarterDO>()
.eq(ProjectPlanningQuarterDO::getPlanningId, planningId)
.isNull(ProjectPlanningQuarterDO::getGuideDetailId)
.ne(excludeId != null, ProjectPlanningQuarterDO::getId, excludeId)) > 0;
}
default boolean existsGuideDetailQuarter(Long planningId, Long excludeId) {
return selectCount(new LambdaQueryWrapperX<ProjectPlanningQuarterDO>()
.eq(ProjectPlanningQuarterDO::getPlanningId, planningId)
.isNotNull(ProjectPlanningQuarterDO::getGuideDetailId)
.ne(excludeId != null, ProjectPlanningQuarterDO::getId, excludeId)) > 0;
}
default List<ProjectPlanningQuarterDO> selectListByPlanningIds(Collection<Long> planningIds) { default List<ProjectPlanningQuarterDO> selectListByPlanningIds(Collection<Long> planningIds) {
if (planningIds == null || planningIds.isEmpty()) { if (planningIds == null || planningIds.isEmpty()) {
return Collections.emptyList(); return Collections.emptyList();
} }
return selectList(new LambdaQueryWrapperX<ProjectPlanningQuarterDO>() return selectList(new LambdaQueryWrapperX<ProjectPlanningQuarterDO>()
.in(ProjectPlanningQuarterDO::getPlanningId, planningIds) .in(ProjectPlanningQuarterDO::getPlanningId, planningIds)
.orderByAsc(ProjectPlanningQuarterDO::getPlanningId)
.orderByAsc(ProjectPlanningQuarterDO::getGuideDetailSortNo)
.orderByAsc(ProjectPlanningQuarterDO::getGuideDetailId)
.orderByAsc(ProjectPlanningQuarterDO::getDistributionYear) .orderByAsc(ProjectPlanningQuarterDO::getDistributionYear)
.orderByAsc(ProjectPlanningQuarterDO::getQuarterNo) .orderByAsc(ProjectPlanningQuarterDO::getQuarterNo)
.orderByAsc(ProjectPlanningQuarterDO::getId)); .orderByAsc(ProjectPlanningQuarterDO::getId));

View File

@@ -0,0 +1,24 @@
package cn.iocoder.lyzsys.module.tjt.dal.mysql.profit;
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.profit.ProjectCostMeasureSnapshotDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface ProjectCostMeasureSnapshotMapper extends BaseMapperX<ProjectCostMeasureSnapshotDO> {
default ProjectCostMeasureSnapshotDO selectByProjectIdAndType(Long projectId, String snapshotType) {
return selectOne(new LambdaQueryWrapperX<ProjectCostMeasureSnapshotDO>()
.eq(ProjectCostMeasureSnapshotDO::getProjectId, projectId)
.eq(ProjectCostMeasureSnapshotDO::getSnapshotType, snapshotType));
}
default List<ProjectCostMeasureSnapshotDO> selectListByProjectId(Long projectId) {
return selectList(new LambdaQueryWrapperX<ProjectCostMeasureSnapshotDO>()
.eq(ProjectCostMeasureSnapshotDO::getProjectId, projectId));
}
}

View File

@@ -22,8 +22,7 @@ public interface ProjectMapper extends BaseMapperX<ProjectDO> {
.eqIfPresent(ProjectDO::getProjectStartYear, reqVO.getProjectStartYear()) .eqIfPresent(ProjectDO::getProjectStartYear, reqVO.getProjectStartYear())
.eqIfPresent(ProjectDO::getProjectStatus, reqVO.getProjectStatus()) .eqIfPresent(ProjectDO::getProjectStatus, reqVO.getProjectStatus())
.betweenIfPresent(ProjectDO::getCreateTime, reqVO.getCreateTime()) .betweenIfPresent(ProjectDO::getCreateTime, reqVO.getCreateTime())
.orderByAsc(ProjectDO::getSortNo) .last("ORDER BY CASE WHEN sort_no IS NULL OR sort_no = N'' THEN 1 ELSE 0 END, sort_no ASC, id ASC"));
.orderByAsc(ProjectDO::getId));
} }
} }

View File

@@ -34,6 +34,19 @@ public interface ProjectRolePersonMapper extends BaseMapperX<ProjectRolePersonDO
.orderByAsc(ProjectRolePersonDO::getId)); .orderByAsc(ProjectRolePersonDO::getId));
} }
default List<ProjectRolePersonDO> selectListByEmployeeIds(Collection<Long> employeeIds) {
if (employeeIds == null || employeeIds.isEmpty()) {
return Collections.emptyList();
}
return selectList(new LambdaQueryWrapperX<ProjectRolePersonDO>()
.in(ProjectRolePersonDO::getEmployeeId, employeeIds)
.eq(ProjectRolePersonDO::getEnabledFlag, Boolean.TRUE)
.orderByAsc(ProjectRolePersonDO::getProjectId)
.orderByAsc(ProjectRolePersonDO::getRoleCode)
.orderByAsc(ProjectRolePersonDO::getSortNo)
.orderByAsc(ProjectRolePersonDO::getId));
}
default Long selectCountByEmployeeId(Long employeeId) { default Long selectCountByEmployeeId(Long employeeId) {
return selectCount(new LambdaQueryWrapperX<ProjectRolePersonDO>() return selectCount(new LambdaQueryWrapperX<ProjectRolePersonDO>()
.eq(ProjectRolePersonDO::getEmployeeId, employeeId)); .eq(ProjectRolePersonDO::getEmployeeId, employeeId));

View File

@@ -5,6 +5,8 @@ import cn.iocoder.lyzsys.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.specialtyrolesplit.SpecialtyRoleSplitDO; import cn.iocoder.lyzsys.module.tjt.dal.dataobject.specialtyrolesplit.SpecialtyRoleSplitDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
import java.util.Collections;
import java.util.List; import java.util.List;
/** /**
@@ -22,9 +24,15 @@ public interface SpecialtyRoleSplitMapper extends BaseMapperX<SpecialtyRoleSplit
.orderByAsc(SpecialtyRoleSplitDO::getId)); .orderByAsc(SpecialtyRoleSplitDO::getId));
} }
default List<SpecialtyRoleSplitDO> selectListByPersonsJsonKeyword(String keyword) { default List<SpecialtyRoleSplitDO> selectListByOutputSplitIds(Collection<Long> outputSplitIds) {
if (outputSplitIds == null || outputSplitIds.isEmpty()) {
return Collections.emptyList();
}
return selectList(new LambdaQueryWrapperX<SpecialtyRoleSplitDO>() return selectList(new LambdaQueryWrapperX<SpecialtyRoleSplitDO>()
.like(SpecialtyRoleSplitDO::getPersonsJson, keyword)); .in(SpecialtyRoleSplitDO::getOutputSplitId, outputSplitIds)
.orderByAsc(SpecialtyRoleSplitDO::getOutputSplitId)
.orderByAsc(SpecialtyRoleSplitDO::getSortNo)
.orderByAsc(SpecialtyRoleSplitDO::getId));
} }
} }

View File

@@ -0,0 +1,105 @@
package cn.iocoder.lyzsys.module.tjt.dal.mysql.specialtyrolesplitperson;
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.specialtyrolesplitperson.SpecialtyRoleSplitPersonDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* 页面 5 角色人员分配明细 Mapper
*
* @author Codex
*/
@Mapper
public interface SpecialtyRoleSplitPersonMapper extends BaseMapperX<SpecialtyRoleSplitPersonDO> {
default List<SpecialtyRoleSplitPersonDO> selectListByRoleSplitId(Long roleSplitId) {
return selectList(new LambdaQueryWrapperX<SpecialtyRoleSplitPersonDO>()
.eq(SpecialtyRoleSplitPersonDO::getRoleSplitId, roleSplitId)
.orderByAsc(SpecialtyRoleSplitPersonDO::getSortNo)
.orderByAsc(SpecialtyRoleSplitPersonDO::getId));
}
default List<SpecialtyRoleSplitPersonDO> selectListByRoleSplitIds(Collection<Long> roleSplitIds) {
if (roleSplitIds == null || roleSplitIds.isEmpty()) {
return Collections.emptyList();
}
return selectList(new LambdaQueryWrapperX<SpecialtyRoleSplitPersonDO>()
.in(SpecialtyRoleSplitPersonDO::getRoleSplitId, roleSplitIds)
.orderByAsc(SpecialtyRoleSplitPersonDO::getRoleSplitId)
.orderByAsc(SpecialtyRoleSplitPersonDO::getSortNo)
.orderByAsc(SpecialtyRoleSplitPersonDO::getId));
}
default List<SpecialtyRoleSplitPersonDO> selectListByOutputSplitIds(Collection<Long> outputSplitIds) {
if (outputSplitIds == null || outputSplitIds.isEmpty()) {
return Collections.emptyList();
}
return selectList(new LambdaQueryWrapperX<SpecialtyRoleSplitPersonDO>()
.in(SpecialtyRoleSplitPersonDO::getOutputSplitId, outputSplitIds)
.orderByAsc(SpecialtyRoleSplitPersonDO::getOutputSplitId)
.orderByAsc(SpecialtyRoleSplitPersonDO::getRoleSplitId)
.orderByAsc(SpecialtyRoleSplitPersonDO::getSortNo)
.orderByAsc(SpecialtyRoleSplitPersonDO::getId));
}
default List<SpecialtyRoleSplitPersonDO> selectListByEmployeeIds(Collection<Long> employeeIds) {
if (employeeIds == null || employeeIds.isEmpty()) {
return Collections.emptyList();
}
return selectList(new LambdaQueryWrapperX<SpecialtyRoleSplitPersonDO>()
.in(SpecialtyRoleSplitPersonDO::getEmployeeId, employeeIds)
.orderByAsc(SpecialtyRoleSplitPersonDO::getPlanningId)
.orderByAsc(SpecialtyRoleSplitPersonDO::getRoleSplitId)
.orderByAsc(SpecialtyRoleSplitPersonDO::getSortNo)
.orderByAsc(SpecialtyRoleSplitPersonDO::getId));
}
default List<SpecialtyRoleSplitPersonDO> selectListByPlanningIdsAndEmployeeIds(Collection<Long> planningIds,
Collection<Long> employeeIds) {
if (planningIds == null || planningIds.isEmpty() || employeeIds == null || employeeIds.isEmpty()) {
return Collections.emptyList();
}
return selectList(new LambdaQueryWrapperX<SpecialtyRoleSplitPersonDO>()
.in(SpecialtyRoleSplitPersonDO::getPlanningId, planningIds)
.in(SpecialtyRoleSplitPersonDO::getEmployeeId, employeeIds)
.orderByAsc(SpecialtyRoleSplitPersonDO::getPlanningId)
.orderByAsc(SpecialtyRoleSplitPersonDO::getRoleSplitId)
.orderByAsc(SpecialtyRoleSplitPersonDO::getSortNo)
.orderByAsc(SpecialtyRoleSplitPersonDO::getId));
}
default void deleteByRoleSplitId(Long roleSplitId) {
delete(SpecialtyRoleSplitPersonDO::getRoleSplitId, roleSplitId);
}
default void deleteByRoleSplitIds(Collection<Long> roleSplitIds) {
if (roleSplitIds == null || roleSplitIds.isEmpty()) {
return;
}
delete(new LambdaQueryWrapperX<SpecialtyRoleSplitPersonDO>()
.in(SpecialtyRoleSplitPersonDO::getRoleSplitId, roleSplitIds));
}
default void deleteByOutputSplitId(Long outputSplitId) {
delete(SpecialtyRoleSplitPersonDO::getOutputSplitId, outputSplitId);
}
default void deleteByOutputSplitIds(Collection<Long> outputSplitIds) {
if (outputSplitIds == null || outputSplitIds.isEmpty()) {
return;
}
delete(new LambdaQueryWrapperX<SpecialtyRoleSplitPersonDO>()
.in(SpecialtyRoleSplitPersonDO::getOutputSplitId, outputSplitIds));
}
default Long selectCountByEmployeeId(Long employeeId) {
return selectCount(new LambdaQueryWrapperX<SpecialtyRoleSplitPersonDO>()
.eq(SpecialtyRoleSplitPersonDO::getEmployeeId, employeeId));
}
}

View File

@@ -11,6 +11,7 @@ public interface ErrorCodeConstants {
// ========== 项目管理 1-020-001-000 ========== // ========== 项目管理 1-020-001-000 ==========
ErrorCode PROJECT_NOT_EXISTS = new ErrorCode(1_020_001_000, "项目不存在"); ErrorCode PROJECT_NOT_EXISTS = new ErrorCode(1_020_001_000, "项目不存在");
ErrorCode PROJECT_STATUS_INVALID = new ErrorCode(1_020_001_001, "项目状态不正确");
// ========== 合约规划管理 1-020-002-000 ========== // ========== 合约规划管理 1-020-002-000 ==========
ErrorCode PROJECT_PLANNING_NOT_EXISTS = new ErrorCode(1_020_002_000, "合约规划不存在"); ErrorCode PROJECT_PLANNING_NOT_EXISTS = new ErrorCode(1_020_002_000, "合约规划不存在");
@@ -25,11 +26,16 @@ public interface ErrorCodeConstants {
ErrorCode PROJECT_PLANNING_DESIGN_PART_INVALID = new ErrorCode(1_020_002_009, "设计部位不正确"); ErrorCode PROJECT_PLANNING_DESIGN_PART_INVALID = new ErrorCode(1_020_002_009, "设计部位不正确");
ErrorCode PROJECT_PLANNING_GUIDE_DETAIL_NOT_EXISTS = new ErrorCode(1_020_002_010, "指导价法明细不存在"); ErrorCode PROJECT_PLANNING_GUIDE_DETAIL_NOT_EXISTS = new ErrorCode(1_020_002_010, "指导价法明细不存在");
ErrorCode PROJECT_PLANNING_GUIDE_DETAIL_SCENE_INVALID = new ErrorCode(1_020_002_011, "当前合约规划不是专业所指导价法,不能维护指导价法明细"); ErrorCode PROJECT_PLANNING_GUIDE_DETAIL_SCENE_INVALID = new ErrorCode(1_020_002_011, "当前合约规划不是专业所指导价法,不能维护指导价法明细");
ErrorCode PROJECT_PLANNING_DESIGN_STAGE_INVALID = new ErrorCode(1_020_002_012, "设计阶段不正确");
// ========== 季度分配管理 1-020-003-000 ========== // ========== 季度分配管理 1-020-003-000 ==========
ErrorCode PROJECT_PLANNING_QUARTER_NOT_EXISTS = new ErrorCode(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_DUPLICATE = new ErrorCode(1_020_003_001, "同一合约规划下该年度季度分配已存在");
ErrorCode PROJECT_PLANNING_QUARTER_PLANNING_NOT_EXISTS = new ErrorCode(1_020_003_002, "关联合约规划不存在"); ErrorCode PROJECT_PLANNING_QUARTER_PLANNING_NOT_EXISTS = new ErrorCode(1_020_003_002, "关联合约规划不存在");
ErrorCode PROJECT_PLANNING_QUARTER_GUIDE_DETAIL_REQUIRED = new ErrorCode(1_020_003_003, "专业所指导价法季度分配必须选择指导价法明细");
ErrorCode PROJECT_PLANNING_QUARTER_GUIDE_DETAIL_INVALID = new ErrorCode(1_020_003_004, "指导价法明细不属于当前合约规划");
ErrorCode PROJECT_PLANNING_QUARTER_GUIDE_DETAIL_NOT_ALLOWED = new ErrorCode(1_020_003_005, "非专业所指导价法季度分配不能选择指导价法明细");
ErrorCode PROJECT_PLANNING_QUARTER_SCOPE_MIXED = new ErrorCode(1_020_003_006, "当前合约规划同时存在父级和明细季度分配,请先清理后再保存");
// ========== 页面 4 拆分管理 1-020-004-000 ========== // ========== 页面 4 拆分管理 1-020-004-000 ==========
ErrorCode PROJECT_OUTPUT_SPLIT_PLANNING_NOT_EXISTS = new ErrorCode(1_020_004_000, "关联合约规划不存在"); ErrorCode PROJECT_OUTPUT_SPLIT_PLANNING_NOT_EXISTS = new ErrorCode(1_020_004_000, "关联合约规划不存在");
@@ -55,9 +61,20 @@ public interface ErrorCodeConstants {
// ========== 员工管理 1-020-008-000 ========== // ========== 员工管理 1-020-008-000 ==========
ErrorCode EMPLOYEE_NOT_EXISTS = new ErrorCode(1_020_008_000, "员工记录不存在"); ErrorCode EMPLOYEE_NOT_EXISTS = new ErrorCode(1_020_008_000, "员工记录不存在");
ErrorCode EMPLOYEE_IN_USE = new ErrorCode(1_020_008_001, "当前员工已被业务数据引用,不能删除"); ErrorCode EMPLOYEE_IN_USE = new ErrorCode(1_020_008_001, "当前员工已被业务数据引用,不能删除");
ErrorCode EMPLOYEE_NOT_OFFICE_LEADER = new ErrorCode(1_020_008_002, "当前员工未启用或未标记为所长,不能维护年度所长考核产值");
// ========== 员工年度成本预算 1-020-009-000 ========== // ========== 员工年度成本预算 1-020-009-000 ==========
ErrorCode EMPLOYEE_YEAR_COST_BUDGET_NOT_EXISTS = new ErrorCode(1_020_009_000, "员工年度成本预算记录不存在"); ErrorCode EMPLOYEE_YEAR_COST_BUDGET_NOT_EXISTS = new ErrorCode(1_020_009_000, "员工年度成本预算记录不存在");
ErrorCode EMPLOYEE_YEAR_COST_BUDGET_DUPLICATE = new ErrorCode(1_020_009_001, "当前员工该年度预计发生成本已存在"); ErrorCode EMPLOYEE_YEAR_COST_BUDGET_DUPLICATE = new ErrorCode(1_020_009_001, "当前员工该年度预计发生成本已存在");
// ========== 年度所长考核产值 1-020-010-000 ==========
ErrorCode EMPLOYEE_YEAR_LEADER_OUTPUT_NOT_EXISTS = new ErrorCode(1_020_010_000, "年度所长考核产值记录不存在");
ErrorCode EMPLOYEE_YEAR_LEADER_OUTPUT_DUPLICATE = new ErrorCode(1_020_010_001, "当前所长该年度考核产值已存在");
// ========== 项目成本测算快照 1-020-011-000 ==========
ErrorCode PROJECT_COST_MEASURE_BUDGET_LOCKED = new ErrorCode(1_020_011_000, "目标责任书已下达,不能重复操作");
ErrorCode PROJECT_COST_MEASURE_ACCOUNTING_LOCKED = new ErrorCode(1_020_011_001, "竣工验收已完成,不能重复操作");
ErrorCode PROJECT_COST_MEASURE_ACCOUNTING_REQUIRED = new ErrorCode(1_020_011_002, "请先完成竣工验收,生成项目成本核算测算后再维护结算测算");
ErrorCode PROJECT_COST_MEASURE_BUDGET_REQUIRED = new ErrorCode(1_020_011_003, "请先下达目标责任书,生成项目成本预算测算后再完成竣工验收");
} }

View File

@@ -15,55 +15,55 @@ import java.util.Map;
*/ */
public final class OutputSplitBizConstants { public final class OutputSplitBizConstants {
public static final String SPECIALTY_PROJECT_LEAD = "project_lead"; public static final String SPECIALTY_PROJECT_LEAD = OutputSplitSpecialtyEnum.PROJECT_LEAD.getCode();
public static final String SPECIALTY_ARCH = "arch"; public static final String SPECIALTY_ARCH = OutputSplitSpecialtyEnum.ARCH.getCode();
public static final String SPECIALTY_DECOR = "decor"; public static final String SPECIALTY_DECOR = OutputSplitSpecialtyEnum.DECOR.getCode();
public static final String SPECIALTY_STRUCT = "struct"; public static final String SPECIALTY_STRUCT = OutputSplitSpecialtyEnum.STRUCT.getCode();
public static final String SPECIALTY_WATER = "water"; public static final String SPECIALTY_WATER = OutputSplitSpecialtyEnum.WATER.getCode();
public static final String SPECIALTY_ELEC = "elec"; public static final String SPECIALTY_ELEC = OutputSplitSpecialtyEnum.ELEC.getCode();
public static final String SPECIALTY_HVAC = "hvac"; public static final String SPECIALTY_HVAC = OutputSplitSpecialtyEnum.HVAC.getCode();
public static final String SPECIALTY_DIGITAL = "digital"; public static final String SPECIALTY_DIGITAL = OutputSplitSpecialtyEnum.DIGITAL.getCode();
public static final String ROLE_DIRECTOR = "director"; public static final String ROLE_DIRECTOR = OutputSplitRoleEnum.DIRECTOR.getCode();
public static final String ROLE_CHECK = "check"; public static final String ROLE_CHECK = OutputSplitRoleEnum.CHECK.getCode();
public static final String ROLE_REVIEW = "review"; public static final String ROLE_REVIEW = OutputSplitRoleEnum.REVIEW.getCode();
public static final String ROLE_APPROVE = "approve"; public static final String ROLE_APPROVE = OutputSplitRoleEnum.APPROVE.getCode();
public static final String ROLE_DESIGN = "design"; public static final String ROLE_DESIGN = OutputSplitRoleEnum.DESIGN.getCode();
public static final String ROLE_PROJECT_MANAGER = "project_manager"; public static final String ROLE_PROJECT_MANAGER = OutputSplitRoleEnum.PROJECT_MANAGER.getCode();
public static final String ROLE_ENGINEERING_PRINCIPAL = "engineering_principal"; public static final String ROLE_ENGINEERING_PRINCIPAL = OutputSplitRoleEnum.ENGINEERING_PRINCIPAL.getCode();
public static final List<SpecialtyItem> ASSIGNMENT_SPECIALTY_ITEMS = Arrays.asList( public static final List<SpecialtyItem> ASSIGNMENT_SPECIALTY_ITEMS = Arrays.asList(
new SpecialtyItem(SPECIALTY_PROJECT_LEAD, "项目经理/工程负责人", 0), new SpecialtyItem(SPECIALTY_PROJECT_LEAD, OutputSplitSpecialtyEnum.PROJECT_LEAD.getLabel(), 0),
new SpecialtyItem(SPECIALTY_ARCH, "建筑", 1), new SpecialtyItem(SPECIALTY_ARCH, OutputSplitSpecialtyEnum.ARCH.getLabel(), 1),
new SpecialtyItem(SPECIALTY_DECOR, "装饰", 2), new SpecialtyItem(SPECIALTY_DECOR, OutputSplitSpecialtyEnum.DECOR.getLabel(), 2),
new SpecialtyItem(SPECIALTY_STRUCT, "结构", 3), new SpecialtyItem(SPECIALTY_STRUCT, OutputSplitSpecialtyEnum.STRUCT.getLabel(), 3),
new SpecialtyItem(SPECIALTY_WATER, "给排水", 4), new SpecialtyItem(SPECIALTY_WATER, OutputSplitSpecialtyEnum.WATER.getLabel(), 4),
new SpecialtyItem(SPECIALTY_ELEC, "电气", 5), new SpecialtyItem(SPECIALTY_ELEC, OutputSplitSpecialtyEnum.ELEC.getLabel(), 5),
new SpecialtyItem(SPECIALTY_HVAC, "暖通", 6), new SpecialtyItem(SPECIALTY_HVAC, OutputSplitSpecialtyEnum.HVAC.getLabel(), 6),
new SpecialtyItem(SPECIALTY_DIGITAL, "数字化设计", 7) new SpecialtyItem(SPECIALTY_DIGITAL, OutputSplitSpecialtyEnum.DIGITAL.getLabel(), 7)
); );
public static final List<SpecialtyItem> SPECIALTY_ITEMS = Arrays.asList( public static final List<SpecialtyItem> SPECIALTY_ITEMS = Arrays.asList(
new SpecialtyItem(SPECIALTY_ARCH, "建筑", 1), new SpecialtyItem(SPECIALTY_ARCH, OutputSplitSpecialtyEnum.ARCH.getLabel(), 1),
new SpecialtyItem(SPECIALTY_DECOR, "装饰", 2), new SpecialtyItem(SPECIALTY_DECOR, OutputSplitSpecialtyEnum.DECOR.getLabel(), 2),
new SpecialtyItem(SPECIALTY_STRUCT, "结构", 3), new SpecialtyItem(SPECIALTY_STRUCT, OutputSplitSpecialtyEnum.STRUCT.getLabel(), 3),
new SpecialtyItem(SPECIALTY_WATER, "给排水", 4), new SpecialtyItem(SPECIALTY_WATER, OutputSplitSpecialtyEnum.WATER.getLabel(), 4),
new SpecialtyItem(SPECIALTY_ELEC, "电气", 5), new SpecialtyItem(SPECIALTY_ELEC, OutputSplitSpecialtyEnum.ELEC.getLabel(), 5),
new SpecialtyItem(SPECIALTY_HVAC, "暖通", 6), new SpecialtyItem(SPECIALTY_HVAC, OutputSplitSpecialtyEnum.HVAC.getLabel(), 6),
new SpecialtyItem(SPECIALTY_DIGITAL, "数字化设计", 7) new SpecialtyItem(SPECIALTY_DIGITAL, OutputSplitSpecialtyEnum.DIGITAL.getLabel(), 7)
); );
public static final List<RoleItem> SPECIALTY_ROLE_ITEMS = Arrays.asList( public static final List<RoleItem> SPECIALTY_ROLE_ITEMS = Arrays.asList(
new RoleItem(ROLE_DIRECTOR, "专业负责人", 1), new RoleItem(ROLE_DIRECTOR, OutputSplitRoleEnum.DIRECTOR.getLabel(), 1),
new RoleItem(ROLE_CHECK, "校对", 2), new RoleItem(ROLE_CHECK, OutputSplitRoleEnum.CHECK.getLabel(), 2),
new RoleItem(ROLE_REVIEW, "审核", 3), new RoleItem(ROLE_REVIEW, OutputSplitRoleEnum.REVIEW.getLabel(), 3),
new RoleItem(ROLE_APPROVE, "审定", 4), new RoleItem(ROLE_APPROVE, OutputSplitRoleEnum.APPROVE.getLabel(), 4),
new RoleItem(ROLE_DESIGN, "设计", 5) new RoleItem(ROLE_DESIGN, OutputSplitRoleEnum.DESIGN.getLabel(), 5)
); );
public static final List<RoleItem> PROJECT_LEAD_ROLE_ITEMS = Arrays.asList( public static final List<RoleItem> PROJECT_LEAD_ROLE_ITEMS = Arrays.asList(
new RoleItem(ROLE_PROJECT_MANAGER, "项目经理", 1), new RoleItem(ROLE_PROJECT_MANAGER, OutputSplitRoleEnum.PROJECT_MANAGER.getLabel(), 1),
new RoleItem(ROLE_ENGINEERING_PRINCIPAL, "工程负责人", 2) new RoleItem(ROLE_ENGINEERING_PRINCIPAL, OutputSplitRoleEnum.ENGINEERING_PRINCIPAL.getLabel(), 2)
); );
private OutputSplitBizConstants() { private OutputSplitBizConstants() {

View File

@@ -0,0 +1,44 @@
package cn.iocoder.lyzsys.module.tjt.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 专业内/项目负责人角色编码枚举。
*/
@Getter
@AllArgsConstructor
public enum OutputSplitRoleEnum {
DIRECTOR("director", "专业负责人", 1, false),
CHECK("check", "校对", 2, false),
REVIEW("review", "审核", 3, false),
APPROVE("approve", "审定", 4, false),
DESIGN("design", "设计", 5, false),
PROJECT_MANAGER("project_manager", "项目经理", 1, true),
ENGINEERING_PRINCIPAL("engineering_principal", "工程负责人", 2, true);
private final String code;
private final String label;
private final Integer sortNo;
private final boolean projectLeadRole;
public static OutputSplitRoleEnum of(String code) {
return Arrays.stream(values())
.filter(item -> item.getCode().equals(code))
.findFirst()
.orElse(null);
}
public static boolean contains(String code) {
return of(code) != null;
}
public static String labelOf(String code) {
OutputSplitRoleEnum item = of(code);
return item == null ? code : item.getLabel();
}
}

View File

@@ -0,0 +1,45 @@
package cn.iocoder.lyzsys.module.tjt.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 项目/专业分配专业编码枚举。
*/
@Getter
@AllArgsConstructor
public enum OutputSplitSpecialtyEnum {
PROJECT_LEAD("project_lead", "项目经理/工程负责人", 0, true),
ARCH("arch", "建筑", 1, false),
DECOR("decor", "装饰", 2, false),
STRUCT("struct", "结构", 3, false),
WATER("water", "给排水", 4, false),
ELEC("elec", "电气", 5, false),
HVAC("hvac", "暖通", 6, false),
DIGITAL("digital", "数字化设计", 7, false);
private final String code;
private final String label;
private final Integer sortNo;
private final boolean projectLead;
public static OutputSplitSpecialtyEnum of(String code) {
return Arrays.stream(values())
.filter(item -> item.getCode().equals(code))
.findFirst()
.orElse(null);
}
public static boolean contains(String code) {
return of(code) != null;
}
public static String labelOf(String code) {
OutputSplitSpecialtyEnum item = of(code);
return item == null ? code : item.getLabel();
}
}

View File

@@ -0,0 +1,22 @@
package cn.iocoder.lyzsys.module.tjt.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 项目成本测算快照类型
*
* @author Codex
*/
@Getter
@AllArgsConstructor
public enum ProjectCostMeasureSnapshotTypeEnum {
BUDGET("budget", "项目成本预算测算"),
ACCOUNTING("accounting", "项目成本核算测算"),
SETTLEMENT("settlement", "项目成本结算测算");
private final String code;
private final String label;
}

View File

@@ -1,70 +1,62 @@
package cn.iocoder.lyzsys.module.tjt.enums; package cn.iocoder.lyzsys.module.tjt.enums;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/** /**
* 合约规划业务类型常量 * 合约规划业务类型常量
*
* <p>数据库存储稳定 code页面和 Excel 按 label 展示。</p>
* *
* @author Codex * @author Codex
*/ */
public final class ProjectPlanningBizTypeConstants { public final class ProjectPlanningBizTypeConstants {
public static final String OWNERSHIP_TYPE_MAJOR = "专业所"; public static final String OWNERSHIP_TYPE_MAJOR = ProjectPlanningOwnershipTypeEnum.MAJOR.getCode();
public static final String OWNERSHIP_TYPE_COMPREHENSIVE = "综合所"; public static final String OWNERSHIP_TYPE_COMPREHENSIVE = ProjectPlanningOwnershipTypeEnum.COMPREHENSIVE.getCode();
public static final String OWNERSHIP_TYPE_SUBCONTRACT = "专业分包"; public static final String OWNERSHIP_TYPE_SPECIAL_SUBCONTRACT =
public static final String DESIGN_PART_REAL_ESTATE = "地上部分"; ProjectPlanningOwnershipTypeEnum.SPECIAL_SUBCONTRACT_MAJOR.getCode();
public static final String DESIGN_PART_UNDERGROUND = "地下部分"; public static final String OWNERSHIP_TYPE_SOURCE_COOP_SUBCONTRACT =
ProjectPlanningOwnershipTypeEnum.SPECIAL_SUBCONTRACT_SOURCE_COOP.getCode();
public static final String OWNERSHIP_TYPE_COMPREHENSIVE_SUBCONTRACT =
ProjectPlanningOwnershipTypeEnum.SPECIAL_SUBCONTRACT_COMPREHENSIVE.getCode();
public static final String CALCULATION_METHOD_GUIDANCE_PRICE = "指导价法"; public static final String DESIGN_PART_REAL_ESTATE = ProjectPlanningDesignPartEnum.ABOVE_GROUND.getCode();
public static final String CALCULATION_METHOD_CONTRACT_PRICE = "合同价法"; public static final String DESIGN_PART_UNDERGROUND = ProjectPlanningDesignPartEnum.UNDERGROUND.getCode();
public static final String CALCULATION_METHOD_VIRTUAL_OUTPUT = "虚拟产值法"; public static final String DESIGN_PART_OTHER = ProjectPlanningDesignPartEnum.OTHER.getCode();
public static final String VIRTUAL_CALCULATION_METHOD_GUIDANCE_PRICE = "指导单价法"; public static final String CALCULATION_METHOD_GUIDANCE_PRICE =
public static final String VIRTUAL_CALCULATION_METHOD_GUIDANCE_TOTAL_PRICE = "指导总价法"; ProjectPlanningCalculationMethodEnum.GUIDANCE_PRICE.getCode();
public static final String VIRTUAL_CALCULATION_METHOD_WORKING_DAY = "工日法"; public static final String CALCULATION_METHOD_CONTRACT_PRICE =
ProjectPlanningCalculationMethodEnum.CONTRACT_PRICE.getCode();
public static final String CALCULATION_METHOD_VIRTUAL_OUTPUT =
ProjectPlanningCalculationMethodEnum.VIRTUAL_OUTPUT.getCode();
private static final Set<String> OWNERSHIP_TYPES = new HashSet<>(Arrays.asList( public static final String VIRTUAL_CALCULATION_METHOD_GUIDANCE_PRICE =
OWNERSHIP_TYPE_MAJOR, ProjectPlanningVirtualCalculationMethodEnum.GUIDANCE_PRICE.getCode();
OWNERSHIP_TYPE_COMPREHENSIVE, public static final String VIRTUAL_CALCULATION_METHOD_GUIDANCE_TOTAL_PRICE =
OWNERSHIP_TYPE_SUBCONTRACT ProjectPlanningVirtualCalculationMethodEnum.GUIDANCE_TOTAL_PRICE.getCode();
)); public static final String VIRTUAL_CALCULATION_METHOD_WORKING_DAY =
ProjectPlanningVirtualCalculationMethodEnum.WORKING_DAY.getCode();
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> DESIGN_PARTS = new HashSet<>(Arrays.asList(
DESIGN_PART_REAL_ESTATE,
DESIGN_PART_UNDERGROUND
));
private static final Set<String> VIRTUAL_CALCULATION_METHODS = new HashSet<>(Arrays.asList(
VIRTUAL_CALCULATION_METHOD_GUIDANCE_PRICE,
VIRTUAL_CALCULATION_METHOD_GUIDANCE_TOTAL_PRICE,
VIRTUAL_CALCULATION_METHOD_WORKING_DAY
));
private ProjectPlanningBizTypeConstants() { private ProjectPlanningBizTypeConstants() {
} }
public static boolean isValidOwnershipType(String value) { public static boolean isValidOwnershipType(String value) {
return OWNERSHIP_TYPES.contains(value); return ProjectPlanningOwnershipTypeEnum.contains(value);
} }
public static boolean isValidCalculationMethod(String value) { public static boolean isValidCalculationMethod(String value) {
return CALCULATION_METHODS.contains(value); return ProjectPlanningCalculationMethodEnum.contains(value);
}
public static boolean isValidDesignStage(String value) {
return ProjectPlanningDesignStageEnum.contains(value);
} }
public static boolean isValidDesignPart(String value) { public static boolean isValidDesignPart(String value) {
return DESIGN_PARTS.contains(value); return ProjectPlanningDesignPartEnum.contains(value);
} }
public static boolean isValidVirtualCalculationMethod(String value) { public static boolean isValidVirtualCalculationMethod(String value) {
return VIRTUAL_CALCULATION_METHODS.contains(value); return ProjectPlanningVirtualCalculationMethodEnum.contains(value);
} }
public static boolean isMajor(String value) { public static boolean isMajor(String value) {
@@ -76,7 +68,19 @@ public final class ProjectPlanningBizTypeConstants {
} }
public static boolean isSubcontract(String value) { public static boolean isSubcontract(String value) {
return OWNERSHIP_TYPE_SUBCONTRACT.equals(value); return isSpecialSubcontract(value) || isSourceCoopSubcontract(value) || isComprehensiveSubcontract(value);
}
public static boolean isSpecialSubcontract(String value) {
return OWNERSHIP_TYPE_SPECIAL_SUBCONTRACT.equals(value);
}
public static boolean isSourceCoopSubcontract(String value) {
return OWNERSHIP_TYPE_SOURCE_COOP_SUBCONTRACT.equals(value);
}
public static boolean isComprehensiveSubcontract(String value) {
return OWNERSHIP_TYPE_COMPREHENSIVE_SUBCONTRACT.equals(value);
} }
public static boolean isGuidancePrice(String value) { public static boolean isGuidancePrice(String value) {
@@ -107,4 +111,24 @@ public final class ProjectPlanningBizTypeConstants {
return VIRTUAL_CALCULATION_METHOD_GUIDANCE_TOTAL_PRICE.equals(value); return VIRTUAL_CALCULATION_METHOD_GUIDANCE_TOTAL_PRICE.equals(value);
} }
public static String getOwnershipTypeLabel(String value) {
return ProjectPlanningOwnershipTypeEnum.labelOf(value);
}
public static String getCalculationMethodLabel(String value) {
return ProjectPlanningCalculationMethodEnum.labelOf(value);
}
public static String getDesignStageLabel(String value) {
return ProjectPlanningDesignStageEnum.labelOf(value);
}
public static String getDesignPartLabel(String value) {
return ProjectPlanningDesignPartEnum.labelOf(value);
}
public static String getVirtualCalculationMethodLabel(String value) {
return ProjectPlanningVirtualCalculationMethodEnum.labelOf(value);
}
} }

View File

@@ -0,0 +1,38 @@
package cn.iocoder.lyzsys.module.tjt.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 合约规划产值计算方式枚举。
*/
@Getter
@AllArgsConstructor
public enum ProjectPlanningCalculationMethodEnum {
GUIDANCE_PRICE("guidance_price", "指导价法"),
CONTRACT_PRICE("contract_price", "合同价法"),
VIRTUAL_OUTPUT("virtual_output", "虚拟产值法");
private final String code;
private final String label;
public static ProjectPlanningCalculationMethodEnum of(String code) {
return Arrays.stream(values())
.filter(item -> item.getCode().equals(code))
.findFirst()
.orElse(null);
}
public static boolean contains(String code) {
return of(code) != null;
}
public static String labelOf(String code) {
ProjectPlanningCalculationMethodEnum item = of(code);
return item == null ? code : item.getLabel();
}
}

View File

@@ -0,0 +1,38 @@
package cn.iocoder.lyzsys.module.tjt.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 指导价法设计部位枚举。
*/
@Getter
@AllArgsConstructor
public enum ProjectPlanningDesignPartEnum {
ABOVE_GROUND("above_ground", "地上部分"),
UNDERGROUND("underground", "地下部分"),
OTHER("other", "其他");
private final String code;
private final String label;
public static ProjectPlanningDesignPartEnum of(String code) {
return Arrays.stream(values())
.filter(item -> item.getCode().equals(code))
.findFirst()
.orElse(null);
}
public static boolean contains(String code) {
return of(code) != null;
}
public static String labelOf(String code) {
ProjectPlanningDesignPartEnum item = of(code);
return item == null ? code : item.getLabel();
}
}

View File

@@ -0,0 +1,38 @@
package cn.iocoder.lyzsys.module.tjt.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 合约规划设计阶段枚举。
*/
@Getter
@AllArgsConstructor
public enum ProjectPlanningDesignStageEnum {
SCHEME("scheme", "方案"),
CONSTRUCTION_DRAWING("construction_drawing", "施工图"),
SCHEME_AND_CONSTRUCTION_DRAWING("scheme_and_construction_drawing", "方案+施工图");
private final String code;
private final String label;
public static ProjectPlanningDesignStageEnum of(String code) {
return Arrays.stream(values())
.filter(item -> item.getCode().equals(code))
.findFirst()
.orElse(null);
}
public static boolean contains(String code) {
return of(code) != null;
}
public static String labelOf(String code) {
ProjectPlanningDesignStageEnum item = of(code);
return item == null ? code : item.getLabel();
}
}

View File

@@ -0,0 +1,40 @@
package cn.iocoder.lyzsys.module.tjt.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 合约规划归属类型枚举。
*/
@Getter
@AllArgsConstructor
public enum ProjectPlanningOwnershipTypeEnum {
MAJOR("major", "专业所"),
COMPREHENSIVE("comprehensive", "综合所"),
SPECIAL_SUBCONTRACT_MAJOR("special_subcontract_major", "专项分包-专业所"),
SPECIAL_SUBCONTRACT_SOURCE_COOP("special_subcontract_source_coop", "专项分包-源头合作分包"),
SPECIAL_SUBCONTRACT_COMPREHENSIVE("special_subcontract_comprehensive", "专项分包-综合所");
private final String code;
private final String label;
public static ProjectPlanningOwnershipTypeEnum of(String code) {
return Arrays.stream(values())
.filter(item -> item.getCode().equals(code))
.findFirst()
.orElse(null);
}
public static boolean contains(String code) {
return of(code) != null;
}
public static String labelOf(String code) {
ProjectPlanningOwnershipTypeEnum item = of(code);
return item == null ? code : item.getLabel();
}
}

View File

@@ -0,0 +1,38 @@
package cn.iocoder.lyzsys.module.tjt.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 虚拟产值计算方式枚举。
*/
@Getter
@AllArgsConstructor
public enum ProjectPlanningVirtualCalculationMethodEnum {
GUIDANCE_PRICE("guidance_price", "指导单价法"),
GUIDANCE_TOTAL_PRICE("guidance_total_price", "指导总价法"),
WORKING_DAY("working_day", "工日法");
private final String code;
private final String label;
public static ProjectPlanningVirtualCalculationMethodEnum of(String code) {
return Arrays.stream(values())
.filter(item -> item.getCode().equals(code))
.findFirst()
.orElse(null);
}
public static boolean contains(String code) {
return of(code) != null;
}
public static String labelOf(String code) {
ProjectPlanningVirtualCalculationMethodEnum item = of(code);
return item == null ? code : item.getLabel();
}
}

View File

@@ -0,0 +1,39 @@
package cn.iocoder.lyzsys.module.tjt.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 项目状态枚举。
*/
@Getter
@AllArgsConstructor
public enum ProjectStatusEnum {
IN_PROGRESS("in_progress", "进行中"),
COMPLETED("completed", "完成"),
PAUSED("paused", "暂停"),
TERMINATED("terminated", "中止");
private final String code;
private final String label;
public static ProjectStatusEnum of(String code) {
return Arrays.stream(values())
.filter(item -> item.getCode().equals(code))
.findFirst()
.orElse(null);
}
public static boolean contains(String code) {
return of(code) != null;
}
public static String labelOf(String code) {
ProjectStatusEnum item = of(code);
return item == null ? code : item.getLabel();
}
}

View File

@@ -24,6 +24,7 @@ public interface EmployeeService {
PageResult<EmployeeRespVO> getEmployeePage(EmployeePageReqVO pageReqVO); PageResult<EmployeeRespVO> getEmployeePage(EmployeePageReqVO pageReqVO);
List<EmployeeSimpleRespVO> getEmployeeSimpleList(String keyword, Long officeId, String status, Boolean enabledFlag); List<EmployeeSimpleRespVO> getEmployeeSimpleList(String keyword, Long officeId, String status,
Boolean enabledFlag, Boolean officeLeaderFlag);
} }

View File

@@ -2,21 +2,19 @@ package cn.iocoder.lyzsys.module.tjt.service.employee;
import cn.iocoder.lyzsys.framework.common.pojo.PageResult; import cn.iocoder.lyzsys.framework.common.pojo.PageResult;
import cn.iocoder.lyzsys.framework.common.util.collection.CollectionUtils; import cn.iocoder.lyzsys.framework.common.util.collection.CollectionUtils;
import cn.iocoder.lyzsys.framework.common.util.json.JsonUtils;
import cn.iocoder.lyzsys.framework.common.util.object.BeanUtils; import cn.iocoder.lyzsys.framework.common.util.object.BeanUtils;
import cn.iocoder.lyzsys.module.tjt.controller.admin.employee.vo.EmployeePageReqVO; import cn.iocoder.lyzsys.module.tjt.controller.admin.employee.vo.EmployeePageReqVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.employee.vo.EmployeeRespVO; import cn.iocoder.lyzsys.module.tjt.controller.admin.employee.vo.EmployeeRespVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.employee.vo.EmployeeSaveReqVO; import cn.iocoder.lyzsys.module.tjt.controller.admin.employee.vo.EmployeeSaveReqVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.employee.vo.EmployeeSimpleRespVO; import cn.iocoder.lyzsys.module.tjt.controller.admin.employee.vo.EmployeeSimpleRespVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.specialtyrolesplit.vo.SpecialtyRolePersonSaveReqVO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.employee.EmployeeDO; import cn.iocoder.lyzsys.module.tjt.dal.dataobject.employee.EmployeeDO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.office.OfficeDO; import cn.iocoder.lyzsys.module.tjt.dal.dataobject.office.OfficeDO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.specialtyrolesplit.SpecialtyRoleSplitDO;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.employeeyearcostbudget.EmployeeYearCostBudgetMapper; import cn.iocoder.lyzsys.module.tjt.dal.mysql.employeeyearcostbudget.EmployeeYearCostBudgetMapper;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.employeeyearleaderoutput.EmployeeYearLeaderOutputMapper;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.employee.EmployeeMapper; import cn.iocoder.lyzsys.module.tjt.dal.mysql.employee.EmployeeMapper;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.office.OfficeMapper; import cn.iocoder.lyzsys.module.tjt.dal.mysql.office.OfficeMapper;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.projectroleperson.ProjectRolePersonMapper; import cn.iocoder.lyzsys.module.tjt.dal.mysql.projectroleperson.ProjectRolePersonMapper;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.specialtyrolesplit.SpecialtyRoleSplitMapper; import cn.iocoder.lyzsys.module.tjt.dal.mysql.specialtyrolesplitperson.SpecialtyRoleSplitPersonMapper;
import cn.iocoder.lyzsys.module.tjt.service.office.OfficeService; import cn.iocoder.lyzsys.module.tjt.service.office.OfficeService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@@ -43,9 +41,11 @@ public class EmployeeServiceImpl implements EmployeeService {
@Resource @Resource
private EmployeeYearCostBudgetMapper employeeYearCostBudgetMapper; private EmployeeYearCostBudgetMapper employeeYearCostBudgetMapper;
@Resource @Resource
private EmployeeYearLeaderOutputMapper employeeYearLeaderOutputMapper;
@Resource
private ProjectRolePersonMapper projectRolePersonMapper; private ProjectRolePersonMapper projectRolePersonMapper;
@Resource @Resource
private SpecialtyRoleSplitMapper specialtyRoleSplitMapper; private SpecialtyRoleSplitPersonMapper specialtyRoleSplitPersonMapper;
@Resource @Resource
private OfficeService officeService; private OfficeService officeService;
@@ -56,6 +56,9 @@ public class EmployeeServiceImpl implements EmployeeService {
if (employee.getEnabledFlag() == null) { if (employee.getEnabledFlag() == null) {
employee.setEnabledFlag(Boolean.TRUE); employee.setEnabledFlag(Boolean.TRUE);
} }
if (employee.getOfficeLeaderFlag() == null) {
employee.setOfficeLeaderFlag(Boolean.FALSE);
}
employeeMapper.insert(employee); employeeMapper.insert(employee);
return employee.getId(); return employee.getId();
} }
@@ -64,13 +67,18 @@ public class EmployeeServiceImpl implements EmployeeService {
public void updateEmployee(EmployeeSaveReqVO updateReqVO) { public void updateEmployee(EmployeeSaveReqVO updateReqVO) {
validateEmployeeExists(updateReqVO.getId()); validateEmployeeExists(updateReqVO.getId());
officeService.validateOfficeExists(updateReqVO.getOfficeId()); officeService.validateOfficeExists(updateReqVO.getOfficeId());
employeeMapper.updateById(BeanUtils.toBean(updateReqVO, EmployeeDO.class)); EmployeeDO employee = BeanUtils.toBean(updateReqVO, EmployeeDO.class);
if (employee.getOfficeLeaderFlag() == null) {
employee.setOfficeLeaderFlag(Boolean.FALSE);
}
employeeMapper.updateById(employee);
} }
@Override @Override
public void deleteEmployee(Long id) { public void deleteEmployee(Long id) {
validateEmployeeExists(id); validateEmployeeExists(id);
if (employeeYearCostBudgetMapper.selectCountByEmployeeId(id) > 0 if (employeeYearCostBudgetMapper.selectCountByEmployeeId(id) > 0
|| employeeYearLeaderOutputMapper.selectCountByEmployeeId(id) > 0
|| projectRolePersonMapper.selectCountByEmployeeId(id) > 0 || projectRolePersonMapper.selectCountByEmployeeId(id) > 0
|| existsInSpecialtyRoleSplit(id)) { || existsInSpecialtyRoleSplit(id)) {
throw exception(EMPLOYEE_IN_USE); throw exception(EMPLOYEE_IN_USE);
@@ -104,8 +112,10 @@ public class EmployeeServiceImpl implements EmployeeService {
} }
@Override @Override
public List<EmployeeSimpleRespVO> getEmployeeSimpleList(String keyword, Long officeId, String status, Boolean enabledFlag) { public List<EmployeeSimpleRespVO> getEmployeeSimpleList(String keyword, Long officeId, String status,
List<EmployeeDO> list = employeeMapper.selectSimpleList(keyword, officeId, status, enabledFlag == null ? Boolean.TRUE : enabledFlag); Boolean enabledFlag, Boolean officeLeaderFlag) {
List<EmployeeDO> list = employeeMapper.selectSimpleList(keyword, officeId, status,
enabledFlag == null ? Boolean.TRUE : enabledFlag, officeLeaderFlag);
Map<Long, OfficeDO> officeMap = getOfficeMap(CollectionUtils.convertSet(list, EmployeeDO::getOfficeId)); Map<Long, OfficeDO> officeMap = getOfficeMap(CollectionUtils.convertSet(list, EmployeeDO::getOfficeId));
return BeanUtils.toBean(list, EmployeeSimpleRespVO.class, respVO -> return BeanUtils.toBean(list, EmployeeSimpleRespVO.class, respVO ->
respVO.setOfficeName(officeMap.containsKey(respVO.getOfficeId()) respVO.setOfficeName(officeMap.containsKey(respVO.getOfficeId())
@@ -113,20 +123,7 @@ public class EmployeeServiceImpl implements EmployeeService {
} }
private boolean existsInSpecialtyRoleSplit(Long employeeId) { private boolean existsInSpecialtyRoleSplit(Long employeeId) {
List<SpecialtyRoleSplitDO> candidateList = specialtyRoleSplitMapper.selectListByPersonsJsonKeyword("\"employeeId\":" + employeeId); return specialtyRoleSplitPersonMapper.selectCountByEmployeeId(employeeId) > 0;
for (SpecialtyRoleSplitDO item : candidateList) {
List<SpecialtyRolePersonSaveReqVO> persons = JsonUtils.parseArray(item.getPersonsJson(), SpecialtyRolePersonSaveReqVO.class);
if (persons == null) {
continue;
}
boolean matched = persons.stream()
.filter(Objects::nonNull)
.anyMatch(person -> Objects.equals(person.getEmployeeId(), employeeId));
if (matched) {
return true;
}
}
return false;
} }
private Map<Long, OfficeDO> getOfficeMap(Set<Long> officeIds) { private Map<Long, OfficeDO> getOfficeMap(Set<Long> officeIds) {

View File

@@ -1,9 +1,7 @@
package cn.iocoder.lyzsys.module.tjt.service.employeeyearcostbudget; package cn.iocoder.lyzsys.module.tjt.service.employeeyearcostbudget;
import cn.iocoder.lyzsys.framework.common.pojo.PageResult; import cn.iocoder.lyzsys.framework.common.pojo.PageResult;
import cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearcostbudget.vo.EmployeeYearCostBudgetPageReqVO; import cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearcostbudget.vo.*;
import cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearcostbudget.vo.EmployeeYearCostBudgetRespVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearcostbudget.vo.EmployeeYearCostBudgetSaveReqVO;
import javax.validation.Valid; import javax.validation.Valid;
@@ -11,6 +9,8 @@ public interface EmployeeYearCostBudgetService {
Long createEmployeeYearCostBudget(@Valid EmployeeYearCostBudgetSaveReqVO createReqVO); Long createEmployeeYearCostBudget(@Valid EmployeeYearCostBudgetSaveReqVO createReqVO);
EmployeeYearCostBudgetGenerateRespVO generateEmployeeYearCostBudget(@Valid EmployeeYearCostBudgetGenerateReqVO reqVO);
void updateEmployeeYearCostBudget(@Valid EmployeeYearCostBudgetSaveReqVO updateReqVO); void updateEmployeeYearCostBudget(@Valid EmployeeYearCostBudgetSaveReqVO updateReqVO);
void deleteEmployeeYearCostBudget(Long id); void deleteEmployeeYearCostBudget(Long id);

View File

@@ -2,18 +2,22 @@ package cn.iocoder.lyzsys.module.tjt.service.employeeyearcostbudget;
import cn.iocoder.lyzsys.framework.common.pojo.PageResult; import cn.iocoder.lyzsys.framework.common.pojo.PageResult;
import cn.iocoder.lyzsys.framework.common.util.object.BeanUtils; import cn.iocoder.lyzsys.framework.common.util.object.BeanUtils;
import cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearcostbudget.vo.EmployeeYearCostBudgetPageReqVO; import cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearcostbudget.vo.*;
import cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearcostbudget.vo.EmployeeYearCostBudgetRespVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearcostbudget.vo.EmployeeYearCostBudgetSaveReqVO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.employee.EmployeeDO; import cn.iocoder.lyzsys.module.tjt.dal.dataobject.employee.EmployeeDO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.employeeyearcostbudget.EmployeeYearCostBudgetDO; import cn.iocoder.lyzsys.module.tjt.dal.dataobject.employeeyearcostbudget.EmployeeYearCostBudgetDO;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.employee.EmployeeMapper;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.employeeyearcostbudget.EmployeeYearCostBudgetMapper; import cn.iocoder.lyzsys.module.tjt.dal.mysql.employeeyearcostbudget.EmployeeYearCostBudgetMapper;
import cn.iocoder.lyzsys.module.tjt.service.employee.EmployeeService; import cn.iocoder.lyzsys.module.tjt.service.employee.EmployeeService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import static cn.iocoder.lyzsys.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.lyzsys.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.EMPLOYEE_YEAR_COST_BUDGET_DUPLICATE; import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.EMPLOYEE_YEAR_COST_BUDGET_DUPLICATE;
@@ -26,6 +30,8 @@ public class EmployeeYearCostBudgetServiceImpl implements EmployeeYearCostBudget
@Resource @Resource
private EmployeeYearCostBudgetMapper employeeYearCostBudgetMapper; private EmployeeYearCostBudgetMapper employeeYearCostBudgetMapper;
@Resource @Resource
private EmployeeMapper employeeMapper;
@Resource
private EmployeeService employeeService; private EmployeeService employeeService;
@Override @Override
@@ -41,6 +47,32 @@ public class EmployeeYearCostBudgetServiceImpl implements EmployeeYearCostBudget
return budget.getId(); return budget.getId();
} }
@Override
public EmployeeYearCostBudgetGenerateRespVO generateEmployeeYearCostBudget(EmployeeYearCostBudgetGenerateReqVO reqVO) {
BigDecimal expectedCostAmount = amount(reqVO.getExpectedCostAmount());
List<EmployeeDO> enabledEmployees = employeeMapper.selectEnabledList();
Set<Long> existingEmployeeIds = employeeYearCostBudgetMapper.selectListByBudgetYear(reqVO.getBudgetYear())
.stream()
.map(EmployeeYearCostBudgetDO::getEmployeeId)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
List<EmployeeYearCostBudgetDO> createList = enabledEmployees.stream()
.filter(employee -> !existingEmployeeIds.contains(employee.getId()))
.map(employee -> buildInitialBudget(employee, reqVO.getBudgetYear(), expectedCostAmount))
.collect(Collectors.toList());
if (!createList.isEmpty()) {
employeeYearCostBudgetMapper.insertBatch(createList);
}
EmployeeYearCostBudgetGenerateRespVO respVO = new EmployeeYearCostBudgetGenerateRespVO();
respVO.setBudgetYear(reqVO.getBudgetYear());
respVO.setTotalEnabledEmployeeCount(enabledEmployees.size());
respVO.setCreatedCount(createList.size());
respVO.setSkippedCount(enabledEmployees.size() - createList.size());
return respVO;
}
@Override @Override
public void updateEmployeeYearCostBudget(EmployeeYearCostBudgetSaveReqVO updateReqVO) { public void updateEmployeeYearCostBudget(EmployeeYearCostBudgetSaveReqVO updateReqVO) {
validateExists(updateReqVO.getId()); validateExists(updateReqVO.getId());
@@ -82,4 +114,21 @@ public class EmployeeYearCostBudgetServiceImpl implements EmployeeYearCostBudget
} }
} }
private EmployeeYearCostBudgetDO buildInitialBudget(EmployeeDO employee, Integer budgetYear, BigDecimal expectedCostAmount) {
EmployeeYearCostBudgetDO budget = new EmployeeYearCostBudgetDO();
budget.setEmployeeId(employee.getId());
budget.setEmployeeName(employee.getEmployeeName());
budget.setBudgetYear(budgetYear);
budget.setExpectedCostAmount(expectedCostAmount);
budget.setSortNo(employee.getSortNo() == null ? 0 : employee.getSortNo());
budget.setEnabledFlag(Boolean.TRUE);
budget.setRemark("");
return budget;
}
private BigDecimal amount(BigDecimal value) {
return value == null ? BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP)
: value.setScale(2, RoundingMode.HALF_UP);
}
} }

View File

@@ -0,0 +1,24 @@
package cn.iocoder.lyzsys.module.tjt.service.employeeyearleaderoutput;
import cn.iocoder.lyzsys.framework.common.pojo.PageResult;
import cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearleaderoutput.vo.*;
import javax.validation.Valid;
public interface EmployeeYearLeaderOutputService {
Long createEmployeeYearLeaderOutput(@Valid EmployeeYearLeaderOutputSaveReqVO createReqVO);
EmployeeYearLeaderOutputGenerateRespVO generateEmployeeYearLeaderOutput(
@Valid EmployeeYearLeaderOutputGenerateReqVO reqVO);
void updateEmployeeYearLeaderOutput(@Valid EmployeeYearLeaderOutputSaveReqVO updateReqVO);
void deleteEmployeeYearLeaderOutput(Long id);
EmployeeYearLeaderOutputRespVO getEmployeeYearLeaderOutput(Long id);
PageResult<EmployeeYearLeaderOutputRespVO> getEmployeeYearLeaderOutputPage(
EmployeeYearLeaderOutputPageReqVO pageReqVO);
}

View File

@@ -0,0 +1,148 @@
package cn.iocoder.lyzsys.module.tjt.service.employeeyearleaderoutput;
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.employeeyearleaderoutput.vo.*;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.employee.EmployeeDO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.employeeyearleaderoutput.EmployeeYearLeaderOutputDO;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.employee.EmployeeMapper;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.employeeyearleaderoutput.EmployeeYearLeaderOutputMapper;
import cn.iocoder.lyzsys.module.tjt.service.employee.EmployeeService;
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 java.util.Objects;
import java.util.Set;
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.*;
@Service
@Validated
public class EmployeeYearLeaderOutputServiceImpl implements EmployeeYearLeaderOutputService {
@Resource
private EmployeeYearLeaderOutputMapper employeeYearLeaderOutputMapper;
@Resource
private EmployeeMapper employeeMapper;
@Resource
private EmployeeService employeeService;
@Override
public Long createEmployeeYearLeaderOutput(EmployeeYearLeaderOutputSaveReqVO createReqVO) {
EmployeeDO employee = validateEmployeeIsOfficeLeader(createReqVO.getEmployeeId());
validateDuplicate(null, createReqVO.getEmployeeId(), createReqVO.getOutputYear());
EmployeeYearLeaderOutputDO output = BeanUtils.toBean(createReqVO, EmployeeYearLeaderOutputDO.class);
output.setEmployeeName(employee.getEmployeeName());
output.setLeaderOutputAmount(amount(output.getLeaderOutputAmount()));
if (output.getEnabledFlag() == null) {
output.setEnabledFlag(Boolean.TRUE);
}
employeeYearLeaderOutputMapper.insert(output);
return output.getId();
}
@Override
public EmployeeYearLeaderOutputGenerateRespVO generateEmployeeYearLeaderOutput(
EmployeeYearLeaderOutputGenerateReqVO reqVO) {
BigDecimal leaderOutputAmount = amount(reqVO.getLeaderOutputAmount());
List<EmployeeDO> enabledLeaders = employeeMapper.selectEnabledLeaderList();
Set<Long> existingEmployeeIds = employeeYearLeaderOutputMapper.selectListByOutputYear(reqVO.getOutputYear())
.stream()
.map(EmployeeYearLeaderOutputDO::getEmployeeId)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
List<EmployeeYearLeaderOutputDO> createList = enabledLeaders.stream()
.filter(employee -> !existingEmployeeIds.contains(employee.getId()))
.map(employee -> buildInitialOutput(employee, reqVO.getOutputYear(), leaderOutputAmount))
.collect(Collectors.toList());
if (!createList.isEmpty()) {
employeeYearLeaderOutputMapper.insertBatch(createList);
}
EmployeeYearLeaderOutputGenerateRespVO respVO = new EmployeeYearLeaderOutputGenerateRespVO();
respVO.setOutputYear(reqVO.getOutputYear());
respVO.setTotalEnabledLeaderCount(enabledLeaders.size());
respVO.setCreatedCount(createList.size());
respVO.setSkippedCount(enabledLeaders.size() - createList.size());
return respVO;
}
@Override
public void updateEmployeeYearLeaderOutput(EmployeeYearLeaderOutputSaveReqVO updateReqVO) {
validateExists(updateReqVO.getId());
EmployeeDO employee = validateEmployeeIsOfficeLeader(updateReqVO.getEmployeeId());
validateDuplicate(updateReqVO.getId(), updateReqVO.getEmployeeId(), updateReqVO.getOutputYear());
EmployeeYearLeaderOutputDO updateObj = BeanUtils.toBean(updateReqVO, EmployeeYearLeaderOutputDO.class);
updateObj.setEmployeeName(employee.getEmployeeName());
updateObj.setLeaderOutputAmount(amount(updateObj.getLeaderOutputAmount()));
employeeYearLeaderOutputMapper.updateById(updateObj);
}
@Override
public void deleteEmployeeYearLeaderOutput(Long id) {
validateExists(id);
employeeYearLeaderOutputMapper.deleteById(id);
}
@Override
public EmployeeYearLeaderOutputRespVO getEmployeeYearLeaderOutput(Long id) {
return BeanUtils.toBean(validateExists(id), EmployeeYearLeaderOutputRespVO.class);
}
@Override
public PageResult<EmployeeYearLeaderOutputRespVO> getEmployeeYearLeaderOutputPage(
EmployeeYearLeaderOutputPageReqVO pageReqVO) {
return BeanUtils.toBean(employeeYearLeaderOutputMapper.selectPage(pageReqVO),
EmployeeYearLeaderOutputRespVO.class);
}
private EmployeeYearLeaderOutputDO validateExists(Long id) {
EmployeeYearLeaderOutputDO output = employeeYearLeaderOutputMapper.selectById(id);
if (output == null) {
throw exception(EMPLOYEE_YEAR_LEADER_OUTPUT_NOT_EXISTS);
}
return output;
}
private EmployeeDO validateEmployeeIsOfficeLeader(Long employeeId) {
EmployeeDO employee = employeeService.validateEmployeeExists(employeeId);
if (!Boolean.TRUE.equals(employee.getEnabledFlag()) || !Boolean.TRUE.equals(employee.getOfficeLeaderFlag())) {
throw exception(EMPLOYEE_NOT_OFFICE_LEADER);
}
return employee;
}
private void validateDuplicate(Long id, Long employeeId, Integer outputYear) {
EmployeeYearLeaderOutputDO duplicate =
employeeYearLeaderOutputMapper.selectByEmployeeIdAndOutputYear(employeeId, outputYear);
if (duplicate != null && !Objects.equals(duplicate.getId(), id)) {
throw exception(EMPLOYEE_YEAR_LEADER_OUTPUT_DUPLICATE);
}
}
private EmployeeYearLeaderOutputDO buildInitialOutput(EmployeeDO employee, Integer outputYear,
BigDecimal leaderOutputAmount) {
EmployeeYearLeaderOutputDO output = new EmployeeYearLeaderOutputDO();
output.setEmployeeId(employee.getId());
output.setEmployeeName(employee.getEmployeeName());
output.setOutputYear(outputYear);
output.setLeaderOutputAmount(leaderOutputAmount);
output.setSortNo(employee.getSortNo() == null ? 0 : employee.getSortNo());
output.setEnabledFlag(Boolean.TRUE);
output.setRemark("");
return output;
}
private BigDecimal amount(BigDecimal value) {
return value == null ? BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP)
: value.setScale(2, RoundingMode.HALF_UP);
}
}

View File

@@ -0,0 +1,48 @@
package cn.iocoder.lyzsys.module.tjt.service.outputsplit;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.outputsplit.ProjectOutputSplitDO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planning.ProjectPlanningDO;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* 页面 4 拆分比例默认值构造器。
*
* <p>所有“没有拆分记录时的默认比例”都从这里生成,避免页面、专业内分配、报表之间规则漂移。</p>
*
* @author Codex
*/
public final class ProjectOutputSplitDefaults {
private static final int RATIO_SCALE = 4;
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 ProjectOutputSplitDefaults() {
}
public static ProjectOutputSplitDO build(ProjectPlanningDO planning) {
return build(planning, 0);
}
public static ProjectOutputSplitDO build(ProjectPlanningDO planning, Integer fallbackYear) {
ProjectOutputSplitDO outputSplit = new ProjectOutputSplitDO();
if (planning != null) {
outputSplit.setProjectId(planning.getProjectId());
outputSplit.setPlanningId(planning.getId());
outputSplit.setYear(planning.getPlanningStartYear() == null ? fallbackYear : planning.getPlanningStartYear());
}
outputSplit.setProjectLeadRatio(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;
}
}

View File

@@ -12,6 +12,7 @@ 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.project.ProjectMapper;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.projectroleperson.ProjectRolePersonMapper; import cn.iocoder.lyzsys.module.tjt.dal.mysql.projectroleperson.ProjectRolePersonMapper;
import cn.iocoder.lyzsys.module.tjt.enums.OutputSplitBizConstants; import cn.iocoder.lyzsys.module.tjt.enums.OutputSplitBizConstants;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@@ -61,7 +62,7 @@ public class ProjectOutputSplitServiceImpl implements ProjectOutputSplitService
ProjectDO project = validateProjectExists(planning.getProjectId()); ProjectDO project = validateProjectExists(planning.getProjectId());
ProjectOutputSplitDO outputSplit = projectOutputSplitMapper.selectByPlanningId(planningId); ProjectOutputSplitDO outputSplit = projectOutputSplitMapper.selectByPlanningId(planningId);
if (outputSplit == null) { if (outputSplit == null) {
outputSplit = buildDefaultOutputSplit(planning); outputSplit = ProjectOutputSplitDefaults.build(planning);
} }
return buildRespVO(outputSplit, planning, project); return buildRespVO(outputSplit, planning, project);
} }
@@ -76,7 +77,22 @@ public class ProjectOutputSplitServiceImpl implements ProjectOutputSplitService
outputSplit.setProjectId(planning.getProjectId()); outputSplit.setProjectId(planning.getProjectId());
outputSplit.setYear(getPlanningYear(planning)); outputSplit.setYear(getPlanningYear(planning));
normalizeRatios(outputSplit); normalizeRatios(outputSplit);
projectOutputSplitMapper.insert(outputSplit); try {
projectOutputSplitMapper.insert(outputSplit);
} catch (DuplicateKeyException ex) {
// 并发下可能已由自动创建流程插入,重新查询后继续更新用户提交的比例。
outputSplit = projectOutputSplitMapper.selectByPlanningId(reqVO.getPlanningId());
if (outputSplit == null) {
throw ex;
}
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;
}
} else { } else {
ProjectOutputSplitDO updateObj = BeanUtils.toBean(reqVO, ProjectOutputSplitDO.class); ProjectOutputSplitDO updateObj = BeanUtils.toBean(reqVO, ProjectOutputSplitDO.class);
updateObj.setId(outputSplit.getId()); updateObj.setId(outputSplit.getId());
@@ -96,9 +112,18 @@ public class ProjectOutputSplitServiceImpl implements ProjectOutputSplitService
if (outputSplit != null) { if (outputSplit != null) {
return outputSplit; return outputSplit;
} }
ProjectOutputSplitDO createObj = buildDefaultOutputSplit(planning); ProjectOutputSplitDO createObj = ProjectOutputSplitDefaults.build(planning);
projectOutputSplitMapper.insert(createObj); try {
return createObj; projectOutputSplitMapper.insert(createObj);
return createObj;
} catch (DuplicateKeyException ex) {
// 唯一索引兜底并发创建,同一合约规划已存在时直接复用已有记录。
ProjectOutputSplitDO existing = projectOutputSplitMapper.selectByPlanningId(planningId);
if (existing != null) {
return existing;
}
throw ex;
}
} }
@Override @Override
@@ -180,23 +205,6 @@ public class ProjectOutputSplitServiceImpl implements ProjectOutputSplitService
return project; return project;
} }
private ProjectOutputSplitDO buildDefaultOutputSplit(ProjectPlanningDO planning) {
ProjectOutputSplitDO outputSplit = new ProjectOutputSplitDO();
outputSplit.setProjectId(planning.getProjectId());
outputSplit.setPlanningId(planning.getId());
outputSplit.setYear(getPlanningYear(planning));
outputSplit.setProjectLeadRatio(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) { private Integer getPlanningYear(ProjectPlanningDO planning) {
return planning.getPlanningStartYear() == null ? 0 : planning.getPlanningStartYear(); return planning.getPlanningStartYear() == null ? 0 : planning.getPlanningStartYear();
} }
@@ -251,24 +259,28 @@ public class ProjectOutputSplitServiceImpl implements ProjectOutputSplitService
} }
private BigDecimal getSpecialtyRatio(ProjectOutputSplitDO outputSplit, String specialtyCode) { private BigDecimal getSpecialtyRatio(ProjectOutputSplitDO outputSplit, String specialtyCode) {
switch (specialtyCode) { if (OutputSplitBizConstants.SPECIALTY_ARCH.equals(specialtyCode)) {
case OutputSplitBizConstants.SPECIALTY_ARCH: return ratio(outputSplit.getArchRatio());
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;
} }
if (OutputSplitBizConstants.SPECIALTY_DECOR.equals(specialtyCode)) {
return ratio(outputSplit.getDecorRatio());
}
if (OutputSplitBizConstants.SPECIALTY_STRUCT.equals(specialtyCode)) {
return ratio(outputSplit.getStructRatio());
}
if (OutputSplitBizConstants.SPECIALTY_WATER.equals(specialtyCode)) {
return ratio(outputSplit.getWaterRatio());
}
if (OutputSplitBizConstants.SPECIALTY_ELEC.equals(specialtyCode)) {
return ratio(outputSplit.getElecRatio());
}
if (OutputSplitBizConstants.SPECIALTY_HVAC.equals(specialtyCode)) {
return ratio(outputSplit.getHvacRatio());
}
if (OutputSplitBizConstants.SPECIALTY_DIGITAL.equals(specialtyCode)) {
return ratio(outputSplit.getDigitalRatio());
}
return ZERO_RATIO;
} }
private BigDecimal multiplyAmount(BigDecimal left, BigDecimal right) { private BigDecimal multiplyAmount(BigDecimal left, BigDecimal right) {

View File

@@ -31,6 +31,7 @@ import java.util.Objects;
import static cn.iocoder.lyzsys.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.lyzsys.framework.common.exception.util.ServiceExceptionUtil.exception;
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_CALCULATION_METHOD_INVALID;
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_PLANNING_DESIGN_STAGE_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_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_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_OWNERSHIP_TYPE_INVALID;
@@ -156,18 +157,54 @@ public class ProjectPlanningServiceImpl implements ProjectPlanningService {
if (planningIds == null || planningIds.isEmpty()) { if (planningIds == null || planningIds.isEmpty()) {
return Collections.emptyMap(); return Collections.emptyMap();
} }
List<ProjectPlanningQuarterDO> quarterList = projectPlanningQuarterMapper.selectListByPlanningIds(planningIds); List<Long> validPlanningIds = planningIds.stream()
.filter(Objects::nonNull)
.collect(java.util.stream.Collectors.toList());
if (validPlanningIds.isEmpty()) {
return Collections.emptyMap();
}
Map<Long, ProjectPlanningDO> planningMap = projectPlanningMapper.selectBatchIds(validPlanningIds).stream()
.collect(java.util.stream.Collectors.toMap(ProjectPlanningDO::getId, item -> item, (a, b) -> a));
List<ProjectPlanningQuarterDO> quarterList = projectPlanningQuarterMapper.selectListByPlanningIds(validPlanningIds);
Map<Long, List<ProjectPlanningQuarterDO>> quarterMap = quarterList.stream()
.collect(java.util.stream.Collectors.groupingBy(ProjectPlanningQuarterDO::getPlanningId));
Map<Long, BigDecimal> allocatedAmountMap = new HashMap<>(); Map<Long, BigDecimal> allocatedAmountMap = new HashMap<>();
for (Long planningId : planningIds) { for (Long planningId : validPlanningIds) {
allocatedAmountMap.put(planningId, ZERO_RATIO); allocatedAmountMap.put(planningId, calculateAllocatedRatio(
planningMap.get(planningId),
quarterMap.getOrDefault(planningId, Collections.emptyList())));
} }
for (ProjectPlanningQuarterDO quarter : quarterList) {
allocatedAmountMap.merge(quarter.getPlanningId(), ratio(quarter.getDistributionRatio()), BigDecimal::add);
}
allocatedAmountMap.replaceAll((key, value) -> ratio(value));
return allocatedAmountMap; return allocatedAmountMap;
} }
private BigDecimal calculateAllocatedRatio(ProjectPlanningDO planning, List<ProjectPlanningQuarterDO> quarterList) {
if (quarterList == null || quarterList.isEmpty()) {
return ZERO_RATIO;
}
boolean hasGuideDetailQuarter = quarterList.stream().anyMatch(item -> item.getGuideDetailId() != null);
if (!hasGuideDetailQuarter) {
BigDecimal allocatedRatio = ZERO_RATIO;
for (ProjectPlanningQuarterDO quarter : quarterList) {
allocatedRatio = allocatedRatio.add(ratio(quarter.getDistributionRatio()))
.setScale(RATIO_SCALE, RoundingMode.HALF_UP);
}
return allocatedRatio;
}
if (planning == null) {
return ZERO_RATIO;
}
BigDecimal baseAmount = multiplyAmount(planning.getAssessmentOutputValue(), planning.getTotalDistributionAmount());
if (baseAmount.compareTo(BigDecimal.ZERO) == 0) {
return ZERO_RATIO;
}
BigDecimal allocatedAmount = ZERO_AMOUNT;
for (ProjectPlanningQuarterDO quarter : quarterList) {
allocatedAmount = allocatedAmount.add(amount(quarter.getDistributionAmount()))
.setScale(AMOUNT_SCALE, RoundingMode.HALF_UP);
}
return allocatedAmount.divide(baseAmount, RATIO_SCALE, RoundingMode.HALF_UP);
}
private void validateProjectPlanningForSave(ProjectPlanningSaveReqVO reqVO, ProjectPlanningDO dbPlanning) { private void validateProjectPlanningForSave(ProjectPlanningSaveReqVO reqVO, ProjectPlanningDO dbPlanning) {
if (!ProjectPlanningBizTypeConstants.isValidOwnershipType(reqVO.getOwnershipType())) { if (!ProjectPlanningBizTypeConstants.isValidOwnershipType(reqVO.getOwnershipType())) {
throw exception(PROJECT_PLANNING_OWNERSHIP_TYPE_INVALID); throw exception(PROJECT_PLANNING_OWNERSHIP_TYPE_INVALID);
@@ -181,6 +218,10 @@ public class ProjectPlanningServiceImpl implements ProjectPlanningService {
&& !ProjectPlanningBizTypeConstants.isValidVirtualCalculationMethod(reqVO.getVirtualCalculationMethod())) { && !ProjectPlanningBizTypeConstants.isValidVirtualCalculationMethod(reqVO.getVirtualCalculationMethod())) {
throw exception(PROJECT_PLANNING_VIRTUAL_CALCULATION_METHOD_INVALID); throw exception(PROJECT_PLANNING_VIRTUAL_CALCULATION_METHOD_INVALID);
} }
if (StrUtil.isNotBlank(reqVO.getDesignStage())
&& !ProjectPlanningBizTypeConstants.isValidDesignStage(reqVO.getDesignStage())) {
throw exception(PROJECT_PLANNING_DESIGN_STAGE_INVALID);
}
if (ProjectPlanningBizTypeConstants.isWorkingDay(reqVO.getVirtualCalculationMethod())) { if (ProjectPlanningBizTypeConstants.isWorkingDay(reqVO.getVirtualCalculationMethod())) {
if (reqVO.getWorkingDayCount() == null) { if (reqVO.getWorkingDayCount() == null) {
throw exception(PROJECT_PLANNING_WORKING_DAY_COUNT_REQUIRED); throw exception(PROJECT_PLANNING_WORKING_DAY_COUNT_REQUIRED);
@@ -198,9 +239,6 @@ public class ProjectPlanningServiceImpl implements ProjectPlanningService {
} }
private void prepareProjectPlanning(ProjectPlanningDO planning, ProjectDO project) { private void prepareProjectPlanning(ProjectPlanningDO planning, ProjectDO project) {
if (planning.getSortNo() == null) {
planning.setSortNo(0);
}
if (planning.getPlanningStartYear() == null) { if (planning.getPlanningStartYear() == null) {
planning.setPlanningStartYear(project.getProjectStartYear()); planning.setPlanningStartYear(project.getProjectStartYear());
} }
@@ -245,6 +283,7 @@ public class ProjectPlanningServiceImpl implements ProjectPlanningService {
planning.setWorkingDayUnitPrice(amountNullable(planning.getWorkingDayUnitPrice())); planning.setWorkingDayUnitPrice(amountNullable(planning.getWorkingDayUnitPrice()));
planning.setGuidanceUnitPrice(amountNullable(planning.getGuidanceUnitPrice())); planning.setGuidanceUnitPrice(amountNullable(planning.getGuidanceUnitPrice()));
planning.setGuidanceTotalPrice(amountNullable(planning.getGuidanceTotalPrice())); planning.setGuidanceTotalPrice(amountNullable(planning.getGuidanceTotalPrice()));
planning.setContractUnitPrice(amountNullable(planning.getContractUnitPrice()));
} }
private void calculateProjectPlanning(ProjectPlanningDO planning) { private void calculateProjectPlanning(ProjectPlanningDO planning) {
@@ -253,7 +292,9 @@ public class ProjectPlanningServiceImpl implements ProjectPlanningService {
planning.setProjectBudgetOutputValue(amount(planning.getPlanningAmount() planning.setProjectBudgetOutputValue(amount(planning.getPlanningAmount()
.subtract(planning.getManagementFee()) .subtract(planning.getManagementFee())
.subtract(planning.getVatAmount()))); .subtract(planning.getVatAmount())));
planning.setContractUnitPrice(divideAmount(planning.getPlanningAmount(), planning.getPlanningArea())); if (planning.getContractUnitPrice() == null) {
planning.setContractUnitPrice(divideAmount(planning.getPlanningAmount(), planning.getPlanningArea()));
}
planning.setTotalAdjustmentFactor(ZERO_RATIO); planning.setTotalAdjustmentFactor(ZERO_RATIO);
planning.setAssessmentArea(ZERO_AMOUNT); planning.setAssessmentArea(ZERO_AMOUNT);
planning.setVirtualOutputValue(ZERO_AMOUNT); planning.setVirtualOutputValue(ZERO_AMOUNT);

View File

@@ -84,6 +84,7 @@ public class ProjectPlanningGuideDetailServiceImpl implements ProjectPlanningGui
.filter(id -> !retainedIds.contains(id)) .filter(id -> !retainedIds.contains(id))
.collect(Collectors.toList()); .collect(Collectors.toList());
if (!deletedIds.isEmpty()) { if (!deletedIds.isEmpty()) {
projectPlanningQuarterMapper.deleteBatch(ProjectPlanningQuarterDO::getGuideDetailId, deletedIds);
projectPlanningGuideDetailMapper.deleteBatchIds(deletedIds); projectPlanningGuideDetailMapper.deleteBatchIds(deletedIds);
} }
@@ -96,6 +97,7 @@ public class ProjectPlanningGuideDetailServiceImpl implements ProjectPlanningGui
if (detail == null) { if (detail == null) {
throw exception(PROJECT_PLANNING_GUIDE_DETAIL_NOT_EXISTS); throw exception(PROJECT_PLANNING_GUIDE_DETAIL_NOT_EXISTS);
} }
projectPlanningQuarterMapper.delete(ProjectPlanningQuarterDO::getGuideDetailId, id);
projectPlanningGuideDetailMapper.deleteById(id); projectPlanningGuideDetailMapper.deleteById(id);
recalculatePlanningSummary(detail.getPlanningId()); recalculatePlanningSummary(detail.getPlanningId());
} }
@@ -122,6 +124,7 @@ public class ProjectPlanningGuideDetailServiceImpl implements ProjectPlanningGui
if (planningId == null) { if (planningId == null) {
return; return;
} }
projectPlanningQuarterMapper.delete(ProjectPlanningQuarterDO::getPlanningId, planningId);
projectPlanningGuideDetailMapper.delete(ProjectPlanningGuideDetailDO::getPlanningId, planningId); projectPlanningGuideDetailMapper.delete(ProjectPlanningGuideDetailDO::getPlanningId, planningId);
} }
@@ -130,6 +133,7 @@ public class ProjectPlanningGuideDetailServiceImpl implements ProjectPlanningGui
if (planningIds == null || planningIds.isEmpty()) { if (planningIds == null || planningIds.isEmpty()) {
return; return;
} }
projectPlanningQuarterMapper.deleteBatch(ProjectPlanningQuarterDO::getPlanningId, planningIds);
projectPlanningGuideDetailMapper.deleteBatch(ProjectPlanningGuideDetailDO::getPlanningId, planningIds); projectPlanningGuideDetailMapper.deleteBatch(ProjectPlanningGuideDetailDO::getPlanningId, planningIds);
} }
@@ -175,7 +179,6 @@ public class ProjectPlanningGuideDetailServiceImpl implements ProjectPlanningGui
ProjectPlanningDO updateObj = new ProjectPlanningDO(); ProjectPlanningDO updateObj = new ProjectPlanningDO();
updateObj.setId(planningId); updateObj.setId(planningId);
updateObj.setPlanningArea(totalDesignArea); updateObj.setPlanningArea(totalDesignArea);
updateObj.setContractUnitPrice(divideAmount(planning.getPlanningAmount(), totalDesignArea));
updateObj.setTotalAdjustmentFactor(ZERO_RATIO); updateObj.setTotalAdjustmentFactor(ZERO_RATIO);
updateObj.setAssessmentArea(totalAssessmentArea); updateObj.setAssessmentArea(totalAssessmentArea);
updateObj.setVirtualOutputValue(ZERO_AMOUNT); updateObj.setVirtualOutputValue(ZERO_AMOUNT);
@@ -241,9 +244,22 @@ public class ProjectPlanningGuideDetailServiceImpl implements ProjectPlanningGui
return; return;
} }
List<ProjectPlanningQuarterDO> quarterList = projectPlanningQuarterMapper.selectListByPlanningId(planning.getId()); List<ProjectPlanningQuarterDO> quarterList = projectPlanningQuarterMapper.selectListByPlanningId(planning.getId());
Map<Long, ProjectPlanningGuideDetailDO> guideDetailMap = Collections.emptyMap();
if (isGuideDetailScene(planning)) {
guideDetailMap = CollectionUtils.convertMap(
projectPlanningGuideDetailMapper.selectListByPlanningId(planning.getId()),
ProjectPlanningGuideDetailDO::getId);
}
for (ProjectPlanningQuarterDO quarter : quarterList) { for (ProjectPlanningQuarterDO quarter : quarterList) {
ProjectPlanningGuideDetailDO guideDetail = quarter.getGuideDetailId() == null
? null : guideDetailMap.get(quarter.getGuideDetailId());
BigDecimal assessmentOutputValue = guideDetail == null
? planning.getAssessmentOutputValue() : guideDetail.getAssessmentOutputValue();
if (guideDetail != null) {
quarter.setGuideDetailSortNo(guideDetail.getSortNo());
}
quarter.setDistributionAmount(multiplyAmount( quarter.setDistributionAmount(multiplyAmount(
planning.getAssessmentOutputValue(), assessmentOutputValue,
planning.getTotalDistributionAmount(), planning.getTotalDistributionAmount(),
ratio(quarter.getDistributionRatio()) ratio(quarter.getDistributionRatio())
)); ));

View File

@@ -3,9 +3,12 @@ package cn.iocoder.lyzsys.module.tjt.service.planningquarter;
import cn.iocoder.lyzsys.framework.common.util.object.BeanUtils; 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.controller.admin.planningquarter.vo.ProjectPlanningQuarterSaveReqVO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planning.ProjectPlanningDO; import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planning.ProjectPlanningDO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planningguidedetail.ProjectPlanningGuideDetailDO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planningquarter.ProjectPlanningQuarterDO; 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.planning.ProjectPlanningMapper;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.planningguidedetail.ProjectPlanningGuideDetailMapper;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.planningquarter.ProjectPlanningQuarterMapper; import cn.iocoder.lyzsys.module.tjt.dal.mysql.planningquarter.ProjectPlanningQuarterMapper;
import cn.iocoder.lyzsys.module.tjt.enums.ProjectPlanningBizTypeConstants;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@@ -13,11 +16,16 @@ import javax.annotation.Resource;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.util.List; import java.util.List;
import java.util.Objects;
import static cn.iocoder.lyzsys.framework.common.exception.util.ServiceExceptionUtil.exception; 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_DUPLICATE;
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_PLANNING_QUARTER_GUIDE_DETAIL_INVALID;
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_PLANNING_QUARTER_GUIDE_DETAIL_NOT_ALLOWED;
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_PLANNING_QUARTER_GUIDE_DETAIL_REQUIRED;
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_NOT_EXISTS;
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_PLANNING_QUARTER_PLANNING_NOT_EXISTS; import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_PLANNING_QUARTER_PLANNING_NOT_EXISTS;
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_PLANNING_QUARTER_SCOPE_MIXED;
/** /**
* 季度分配 Service 实现类 * 季度分配 Service 实现类
@@ -35,6 +43,8 @@ public class ProjectPlanningQuarterServiceImpl implements ProjectPlanningQuarter
private ProjectPlanningQuarterMapper projectPlanningQuarterMapper; private ProjectPlanningQuarterMapper projectPlanningQuarterMapper;
@Resource @Resource
private ProjectPlanningMapper projectPlanningMapper; private ProjectPlanningMapper projectPlanningMapper;
@Resource
private ProjectPlanningGuideDetailMapper projectPlanningGuideDetailMapper;
@Override @Override
public Long createProjectPlanningQuarter(ProjectPlanningQuarterSaveReqVO createReqVO) { public Long createProjectPlanningQuarter(ProjectPlanningQuarterSaveReqVO createReqVO) {
@@ -42,10 +52,12 @@ public class ProjectPlanningQuarterServiceImpl implements ProjectPlanningQuarter
if (isZeroQuarter(createReqVO)) { if (isZeroQuarter(createReqVO)) {
return null; return null;
} }
validateQuarterUnique(null, createReqVO.getPlanningId(), ProjectPlanningGuideDetailDO guideDetail = validateGuideDetailScope(planning, createReqVO.getGuideDetailId());
validateScopeNotMixed(null, createReqVO.getPlanningId(), guideDetail);
validateQuarterUnique(null, createReqVO.getPlanningId(), createReqVO.getGuideDetailId(),
createReqVO.getDistributionYear(), createReqVO.getQuarterNo()); createReqVO.getDistributionYear(), createReqVO.getQuarterNo());
ProjectPlanningQuarterDO quarter = BeanUtils.toBean(createReqVO, ProjectPlanningQuarterDO.class); ProjectPlanningQuarterDO quarter = BeanUtils.toBean(createReqVO, ProjectPlanningQuarterDO.class);
prepareQuarter(quarter, planning); prepareQuarter(quarter, planning, guideDetail);
projectPlanningQuarterMapper.insert(quarter); projectPlanningQuarterMapper.insert(quarter);
return quarter.getId(); return quarter.getId();
} }
@@ -58,10 +70,12 @@ public class ProjectPlanningQuarterServiceImpl implements ProjectPlanningQuarter
projectPlanningQuarterMapper.deleteById(dbQuarter.getId()); projectPlanningQuarterMapper.deleteById(dbQuarter.getId());
return; return;
} }
validateQuarterUnique(updateReqVO.getId(), updateReqVO.getPlanningId(), ProjectPlanningGuideDetailDO guideDetail = validateGuideDetailScope(planning, updateReqVO.getGuideDetailId());
validateScopeNotMixed(updateReqVO.getId(), updateReqVO.getPlanningId(), guideDetail);
validateQuarterUnique(updateReqVO.getId(), updateReqVO.getPlanningId(), updateReqVO.getGuideDetailId(),
updateReqVO.getDistributionYear(), updateReqVO.getQuarterNo()); updateReqVO.getDistributionYear(), updateReqVO.getQuarterNo());
ProjectPlanningQuarterDO updateObj = BeanUtils.toBean(updateReqVO, ProjectPlanningQuarterDO.class); ProjectPlanningQuarterDO updateObj = BeanUtils.toBean(updateReqVO, ProjectPlanningQuarterDO.class);
prepareQuarter(updateObj, planning); prepareQuarter(updateObj, planning, guideDetail);
projectPlanningQuarterMapper.updateById(updateObj); projectPlanningQuarterMapper.updateById(updateObj);
} }
@@ -88,9 +102,13 @@ public class ProjectPlanningQuarterServiceImpl implements ProjectPlanningQuarter
return projectPlanningQuarterMapper.selectListByPlanningId(planningId); return projectPlanningQuarterMapper.selectListByPlanningId(planningId);
} }
private void validateQuarterUnique(Long id, Long planningId, Integer distributionYear, Integer quarterNo) { private void validateQuarterUnique(Long id, Long planningId, Long guideDetailId,
ProjectPlanningQuarterDO quarter = projectPlanningQuarterMapper.selectByPlanningIdAndDistributionYearAndQuarter( Integer distributionYear, Integer quarterNo) {
planningId, distributionYear, quarterNo); ProjectPlanningQuarterDO quarter = guideDetailId == null
? projectPlanningQuarterMapper.selectParentByPlanningIdAndDistributionYearAndQuarter(
planningId, distributionYear, quarterNo)
: projectPlanningQuarterMapper.selectByPlanningIdAndGuideDetailIdAndDistributionYearAndQuarter(
planningId, guideDetailId, distributionYear, quarterNo);
if (quarter == null) { if (quarter == null) {
return; return;
} }
@@ -115,14 +133,53 @@ public class ProjectPlanningQuarterServiceImpl implements ProjectPlanningQuarter
return quarter; return quarter;
} }
private ProjectPlanningGuideDetailDO validateGuideDetailScope(ProjectPlanningDO planning, Long guideDetailId) {
boolean guideDetailMode = ProjectPlanningBizTypeConstants.isMajorGuidanceScene(
planning.getOwnershipType(), planning.getCalculationMethod());
if (!guideDetailMode) {
if (guideDetailId != null) {
throw exception(PROJECT_PLANNING_QUARTER_GUIDE_DETAIL_NOT_ALLOWED);
}
return null;
}
if (guideDetailId == null) {
throw exception(PROJECT_PLANNING_QUARTER_GUIDE_DETAIL_REQUIRED);
}
ProjectPlanningGuideDetailDO guideDetail = projectPlanningGuideDetailMapper.selectById(guideDetailId);
if (guideDetail == null || !Objects.equals(guideDetail.getPlanningId(), planning.getId())) {
throw exception(PROJECT_PLANNING_QUARTER_GUIDE_DETAIL_INVALID);
}
return guideDetail;
}
private void validateScopeNotMixed(Long id, Long planningId, ProjectPlanningGuideDetailDO guideDetail) {
boolean savingParentQuarter = guideDetail == null;
boolean mixed = savingParentQuarter
? projectPlanningQuarterMapper.existsGuideDetailQuarter(planningId, id)
: projectPlanningQuarterMapper.existsParentQuarter(planningId, id);
if (mixed) {
throw exception(PROJECT_PLANNING_QUARTER_SCOPE_MIXED);
}
}
private boolean isZeroQuarter(ProjectPlanningQuarterSaveReqVO reqVO) { private boolean isZeroQuarter(ProjectPlanningQuarterSaveReqVO reqVO) {
return ratio(reqVO.getDistributionRatio()).compareTo(BigDecimal.ZERO) == 0; return ratio(reqVO.getDistributionRatio()).compareTo(BigDecimal.ZERO) == 0;
} }
private void prepareQuarter(ProjectPlanningQuarterDO quarter, ProjectPlanningDO planning) { private void prepareQuarter(ProjectPlanningQuarterDO quarter, ProjectPlanningDO planning,
ProjectPlanningGuideDetailDO guideDetail) {
quarter.setDistributionRatio(ratio(quarter.getDistributionRatio())); quarter.setDistributionRatio(ratio(quarter.getDistributionRatio()));
if (guideDetail == null) {
quarter.setGuideDetailId(null);
quarter.setGuideDetailSortNo(null);
} else {
quarter.setGuideDetailId(guideDetail.getId());
quarter.setGuideDetailSortNo(guideDetail.getSortNo());
}
BigDecimal assessmentOutputValue = guideDetail == null
? planning.getAssessmentOutputValue() : guideDetail.getAssessmentOutputValue();
quarter.setDistributionAmount(multiplyAmount( quarter.setDistributionAmount(multiplyAmount(
planning.getAssessmentOutputValue(), assessmentOutputValue,
planning.getTotalDistributionAmount(), planning.getTotalDistributionAmount(),
quarter.getDistributionRatio())); quarter.getDistributionRatio()));
} }

View File

@@ -3,6 +3,7 @@ package cn.iocoder.lyzsys.module.tjt.service.profit;
import cn.iocoder.lyzsys.framework.common.pojo.PageResult; 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.ProjectProfitPageReqVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.profit.vo.ProjectProfitRespVO; import cn.iocoder.lyzsys.module.tjt.controller.admin.profit.vo.ProjectProfitRespVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.profit.vo.ProjectProfitSettlementSaveReqVO;
/** /**
* 项目盈亏 Service 接口 * 项目盈亏 Service 接口
@@ -15,4 +16,10 @@ public interface ProjectProfitService {
PageResult<ProjectProfitRespVO> getProjectProfitPage(ProjectProfitPageReqVO pageReqVO); PageResult<ProjectProfitRespVO> getProjectProfitPage(ProjectProfitPageReqVO pageReqVO);
ProjectProfitRespVO lockBudgetSnapshot(Long projectId);
ProjectProfitRespVO lockAccountingSnapshot(Long projectId);
ProjectProfitRespVO saveSettlementSnapshot(ProjectProfitSettlementSaveReqVO saveReqVO);
} }

View File

@@ -2,17 +2,20 @@ package cn.iocoder.lyzsys.module.tjt.service.profit;
import cn.iocoder.lyzsys.framework.common.pojo.PageResult; import cn.iocoder.lyzsys.framework.common.pojo.PageResult;
import cn.iocoder.lyzsys.framework.common.util.collection.CollectionUtils; import cn.iocoder.lyzsys.framework.common.util.collection.CollectionUtils;
import cn.iocoder.lyzsys.framework.common.util.object.BeanUtils;
import cn.iocoder.lyzsys.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.lyzsys.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.lyzsys.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.lyzsys.module.tjt.controller.admin.profit.vo.ProjectProfitPageReqVO; 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.controller.admin.profit.vo.ProjectProfitRespVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.profit.vo.ProjectProfitSettlementSaveReqVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.profit.vo.ProjectProfitSnapshotRespVO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planning.ProjectPlanningDO; 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.profit.ProjectCostMeasureSnapshotDO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.project.ProjectDO; import cn.iocoder.lyzsys.module.tjt.dal.dataobject.project.ProjectDO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.yearkvalue.YearKValueDO;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.planning.ProjectPlanningMapper; 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.profit.ProjectCostMeasureSnapshotMapper;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.project.ProjectMapper; import cn.iocoder.lyzsys.module.tjt.dal.mysql.project.ProjectMapper;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.yearkvalue.YearKValueMapper; import cn.iocoder.lyzsys.module.tjt.enums.ProjectCostMeasureSnapshotTypeEnum;
import cn.iocoder.lyzsys.module.tjt.enums.ProjectPlanningBizTypeConstants; import cn.iocoder.lyzsys.module.tjt.enums.ProjectPlanningBizTypeConstants;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@@ -20,7 +23,7 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.util.Collection; import java.time.LocalDateTime;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -28,6 +31,10 @@ import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static cn.iocoder.lyzsys.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.lyzsys.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_COST_MEASURE_ACCOUNTING_LOCKED;
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_COST_MEASURE_ACCOUNTING_REQUIRED;
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_COST_MEASURE_BUDGET_LOCKED;
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_COST_MEASURE_BUDGET_REQUIRED;
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_NOT_EXISTS; import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_NOT_EXISTS;
@Service @Service
@@ -36,25 +43,24 @@ public class ProjectProfitServiceImpl implements ProjectProfitService {
private static final BigDecimal ZERO_AMOUNT = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP); 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); private static final BigDecimal ZERO_RATIO = BigDecimal.ZERO.setScale(4, RoundingMode.HALF_UP);
private static final BigDecimal ONE_RATIO = BigDecimal.ONE.setScale(4, RoundingMode.HALF_UP);
private static final BigDecimal DEFAULT_INNOVATION_OUTPUT_RATE = new BigDecimal("0.0100"); private static final BigDecimal DEFAULT_INNOVATION_OUTPUT_RATE = new BigDecimal("0.0100");
private static final BigDecimal DEFAULT_YEAR_K_VALUE = new BigDecimal("0.4000"); private static final BigDecimal ASSESSMENT_COEFFICIENT_EXCELLENT = new BigDecimal("1.0200");
private static final BigDecimal ASSESSMENT_COEFFICIENT_QUALIFIED = new BigDecimal("1.0000");
private static final BigDecimal ASSESSMENT_COEFFICIENT_NEEDS_IMPROVEMENT = new BigDecimal("0.9500");
private static final BigDecimal VAT_INCLUDED_DIVISOR = new BigDecimal("1.06");
@Resource @Resource
private ProjectMapper projectMapper; private ProjectMapper projectMapper;
@Resource @Resource
private ProjectPlanningMapper projectPlanningMapper; private ProjectPlanningMapper projectPlanningMapper;
@Resource @Resource
private ProjectPlanningQuarterMapper projectPlanningQuarterMapper; private ProjectCostMeasureSnapshotMapper projectCostMeasureSnapshotMapper;
@Resource
private YearKValueMapper yearKValueMapper;
@Override @Override
public ProjectProfitRespVO getProjectProfit(Long projectId) { public ProjectProfitRespVO getProjectProfit(Long projectId) {
ProjectDO project = validateProjectExists(projectId); ProjectProfitRespVO respVO = buildCurrentProjectProfit(projectId);
List<ProjectPlanningDO> planningList = projectPlanningMapper.selectList(ProjectPlanningDO::getProjectId, fillSnapshots(respVO);
Collections.singleton(projectId)); return respVO;
return buildProjectProfit(project, planningList);
} }
@Override @Override
@@ -78,48 +84,145 @@ public class ProjectProfitServiceImpl implements ProjectProfitService {
return new PageResult<>(list, pageResult.getTotal()); return new PageResult<>(list, pageResult.getTotal());
} }
@Override
public ProjectProfitRespVO lockBudgetSnapshot(Long projectId) {
ProjectProfitRespVO currentProfit = buildCurrentProjectProfit(projectId);
if (projectCostMeasureSnapshotMapper.selectByProjectIdAndType(projectId,
ProjectCostMeasureSnapshotTypeEnum.BUDGET.getCode()) != null) {
throw exception(PROJECT_COST_MEASURE_BUDGET_LOCKED);
}
ProjectCostMeasureSnapshotDO snapshot = buildSnapshot(currentProfit, ProjectCostMeasureSnapshotTypeEnum.BUDGET.getCode());
snapshot.setLockedFlag(Boolean.TRUE);
fillActionInfo(snapshot);
projectCostMeasureSnapshotMapper.insert(snapshot);
return getProjectProfit(projectId);
}
@Override
public ProjectProfitRespVO lockAccountingSnapshot(Long projectId) {
ProjectProfitRespVO currentProfit = buildCurrentProjectProfit(projectId);
ProjectCostMeasureSnapshotDO budgetSnapshot = projectCostMeasureSnapshotMapper.selectByProjectIdAndType(projectId,
ProjectCostMeasureSnapshotTypeEnum.BUDGET.getCode());
if (budgetSnapshot == null || !Boolean.TRUE.equals(budgetSnapshot.getLockedFlag())) {
throw exception(PROJECT_COST_MEASURE_BUDGET_REQUIRED);
}
if (projectCostMeasureSnapshotMapper.selectByProjectIdAndType(projectId,
ProjectCostMeasureSnapshotTypeEnum.ACCOUNTING.getCode()) != null) {
throw exception(PROJECT_COST_MEASURE_ACCOUNTING_LOCKED);
}
ProjectCostMeasureSnapshotDO snapshot = buildSnapshot(currentProfit, ProjectCostMeasureSnapshotTypeEnum.ACCOUNTING.getCode());
snapshot.setLockedFlag(Boolean.TRUE);
fillActionInfo(snapshot);
projectCostMeasureSnapshotMapper.insert(snapshot);
return getProjectProfit(projectId);
}
@Override
public ProjectProfitRespVO saveSettlementSnapshot(ProjectProfitSettlementSaveReqVO saveReqVO) {
validateProjectExists(saveReqVO.getProjectId());
ProjectCostMeasureSnapshotDO accountingSnapshot = projectCostMeasureSnapshotMapper.selectByProjectIdAndType(
saveReqVO.getProjectId(), ProjectCostMeasureSnapshotTypeEnum.ACCOUNTING.getCode());
if (accountingSnapshot == null || !Boolean.TRUE.equals(accountingSnapshot.getLockedFlag())) {
throw exception(PROJECT_COST_MEASURE_ACCOUNTING_REQUIRED);
}
ProjectCostMeasureSnapshotDO settlementSnapshot = projectCostMeasureSnapshotMapper.selectByProjectIdAndType(
saveReqVO.getProjectId(), ProjectCostMeasureSnapshotTypeEnum.SETTLEMENT.getCode());
boolean create = settlementSnapshot == null;
if (create) {
settlementSnapshot = new ProjectCostMeasureSnapshotDO();
}
copySnapshotValues(accountingSnapshot, settlementSnapshot);
settlementSnapshot.setProjectId(saveReqVO.getProjectId());
settlementSnapshot.setSnapshotType(ProjectCostMeasureSnapshotTypeEnum.SETTLEMENT.getCode());
settlementSnapshot.setLockedFlag(Boolean.FALSE);
settlementSnapshot.setAssessmentResult(saveReqVO.getAssessmentResult());
settlementSnapshot.setAssessmentCoefficient(getAssessmentCoefficient(saveReqVO.getAssessmentResult()));
settlementSnapshot.setRemark(saveReqVO.getRemark());
BigDecimal comprehensiveAccountingOutputValue = amount(accountingSnapshot.getComprehensivePlanningAmount());
BigDecimal majorAccountingOutputValue = amount(accountingSnapshot.getMajorOutputValue());
settlementSnapshot.setComprehensiveAccountingOutputValue(comprehensiveAccountingOutputValue);
settlementSnapshot.setMajorAccountingOutputValue(majorAccountingOutputValue);
settlementSnapshot.setComprehensiveSettlementOutputValue(
multiplyAmount(comprehensiveAccountingOutputValue, settlementSnapshot.getAssessmentCoefficient()));
settlementSnapshot.setMajorSettlementOutputValue(
multiplyAmount(majorAccountingOutputValue, settlementSnapshot.getAssessmentCoefficient()));
fillActionInfo(settlementSnapshot);
if (create) {
projectCostMeasureSnapshotMapper.insert(settlementSnapshot);
} else {
projectCostMeasureSnapshotMapper.updateById(settlementSnapshot);
}
return getProjectProfit(saveReqVO.getProjectId());
}
private ProjectProfitRespVO buildCurrentProjectProfit(Long projectId) {
ProjectDO project = validateProjectExists(projectId);
List<ProjectPlanningDO> planningList = projectPlanningMapper.selectList(ProjectPlanningDO::getProjectId,
Collections.singleton(projectId));
return buildProjectProfit(project, planningList);
}
private ProjectProfitRespVO buildProjectProfit(ProjectDO project, List<ProjectPlanningDO> planningList) { private ProjectProfitRespVO buildProjectProfit(ProjectDO project, List<ProjectPlanningDO> planningList) {
List<ProjectPlanningDO> safePlanningList = planningList == null ? Collections.emptyList() : planningList; List<ProjectPlanningDO> safePlanningList = planningList == null ? Collections.emptyList() : planningList;
BigDecimal comprehensivePlanningAmount = ZERO_AMOUNT; BigDecimal comprehensivePlanningAmount = ZERO_AMOUNT;
BigDecimal subcontractPlanningAmount = ZERO_AMOUNT; BigDecimal specialSubcontractPlanningAmount = ZERO_AMOUNT;
BigDecimal sourceCoopSubcontractPlanningAmount = ZERO_AMOUNT;
BigDecimal comprehensiveSubcontractPlanningAmount = ZERO_AMOUNT;
BigDecimal majorExpectedPerformance = ZERO_AMOUNT;
BigDecimal majorOutputValue = ZERO_AMOUNT; BigDecimal majorOutputValue = ZERO_AMOUNT;
List<ProjectPlanningDO> majorPlanningList = safePlanningList.stream()
.filter(planning -> ProjectPlanningBizTypeConstants.isMajor(planning.getOwnershipType()))
.collect(Collectors.toList());
for (ProjectPlanningDO planning : safePlanningList) { for (ProjectPlanningDO planning : safePlanningList) {
BigDecimal planningBudgetOutputValue = amount(planning.getProjectBudgetOutputValue());
if (ProjectPlanningBizTypeConstants.isComprehensive(planning.getOwnershipType())) { if (ProjectPlanningBizTypeConstants.isComprehensive(planning.getOwnershipType())) {
comprehensivePlanningAmount = comprehensivePlanningAmount.add(amount(planning.getPlanningAmount())); comprehensivePlanningAmount = comprehensivePlanningAmount.add(planningBudgetOutputValue);
continue; continue;
} }
if (ProjectPlanningBizTypeConstants.isSubcontract(planning.getOwnershipType())) { if (ProjectPlanningBizTypeConstants.isSpecialSubcontract(planning.getOwnershipType())) {
subcontractPlanningAmount = subcontractPlanningAmount.add(amount(planning.getPlanningAmount())); specialSubcontractPlanningAmount = specialSubcontractPlanningAmount.add(planningBudgetOutputValue);
continue;
}
if (ProjectPlanningBizTypeConstants.isSourceCoopSubcontract(planning.getOwnershipType())) {
sourceCoopSubcontractPlanningAmount = sourceCoopSubcontractPlanningAmount.add(planningBudgetOutputValue);
continue;
}
if (ProjectPlanningBizTypeConstants.isComprehensiveSubcontract(planning.getOwnershipType())) {
comprehensiveSubcontractPlanningAmount = comprehensiveSubcontractPlanningAmount.add(planningBudgetOutputValue);
continue; continue;
} }
if (ProjectPlanningBizTypeConstants.isMajor(planning.getOwnershipType())) { if (ProjectPlanningBizTypeConstants.isMajor(planning.getOwnershipType())) {
majorExpectedPerformance = majorExpectedPerformance.add(planningBudgetOutputValue);
majorOutputValue = majorOutputValue.add(amount(planning.getAssessmentOutputValue())); majorOutputValue = majorOutputValue.add(amount(planning.getAssessmentOutputValue()));
} }
} }
BigDecimal majorExpectedPerformance = calculateMajorExpectedPerformance(majorPlanningList);
BigDecimal contractAmount = amount(project.getContractAmount()); BigDecimal contractAmount = amount(project.getContractAmount());
BigDecimal contractAmountWithoutVat = taxExcludedAmount(contractAmount);
BigDecimal finalSettlementAmount = amount(project.getFinalSettlementAmount()); BigDecimal finalSettlementAmount = amount(project.getFinalSettlementAmount());
BigDecimal effectiveContractSettlementAmount = finalSettlementAmount.compareTo(BigDecimal.ZERO) > 0
? finalSettlementAmount : contractAmount;
BigDecimal taxExcludedSettlementAmount = taxExcludedAmount(effectiveContractSettlementAmount);
BigDecimal innovationOutputRate = project.getInnovationOutputRate() == null BigDecimal innovationOutputRate = project.getInnovationOutputRate() == null
? DEFAULT_INNOVATION_OUTPUT_RATE : ratio(project.getInnovationOutputRate()); ? DEFAULT_INNOVATION_OUTPUT_RATE : ratio(project.getInnovationOutputRate());
BigDecimal innovationOutputValue = contractAmount.compareTo(BigDecimal.ZERO) <= 0 BigDecimal innovationOutputValue = contractAmount.compareTo(BigDecimal.ZERO) <= 0
? ZERO_AMOUNT ? ZERO_AMOUNT
: contractAmount.multiply(innovationOutputRate).setScale(2, RoundingMode.HALF_UP); : contractAmount.multiply(innovationOutputRate).setScale(2, RoundingMode.HALF_UP);
BigDecimal otherCost = amount(project.getOtherCost()); BigDecimal otherCost = amount(project.getOtherCost());
BigDecimal profitLossValue = finalSettlementAmount BigDecimal subcontractPlanningAmount = specialSubcontractPlanningAmount
.add(sourceCoopSubcontractPlanningAmount)
.add(comprehensiveSubcontractPlanningAmount);
BigDecimal profitLossValue = taxExcludedSettlementAmount
.subtract(comprehensivePlanningAmount) .subtract(comprehensivePlanningAmount)
.subtract(subcontractPlanningAmount) .subtract(subcontractPlanningAmount)
.subtract(majorExpectedPerformance) .subtract(majorExpectedPerformance)
.subtract(innovationOutputValue) .subtract(innovationOutputValue)
.subtract(otherCost) .subtract(otherCost)
.setScale(2, RoundingMode.HALF_UP); .setScale(2, RoundingMode.HALF_UP);
BigDecimal profitLossRate = finalSettlementAmount.compareTo(BigDecimal.ZERO) == 0 BigDecimal profitLossRate = taxExcludedSettlementAmount.compareTo(BigDecimal.ZERO) == 0
? ZERO_RATIO ? ZERO_RATIO
: profitLossValue.divide(finalSettlementAmount, 4, RoundingMode.HALF_UP); : profitLossValue.divide(taxExcludedSettlementAmount, 4, RoundingMode.HALF_UP);
ProjectProfitRespVO respVO = new ProjectProfitRespVO(); ProjectProfitRespVO respVO = new ProjectProfitRespVO();
respVO.setProjectId(project.getId()); respVO.setProjectId(project.getId());
@@ -128,10 +231,15 @@ public class ProjectProfitServiceImpl implements ProjectProfitService {
respVO.setContractSignedFlag(project.getContractSignedFlag()); respVO.setContractSignedFlag(project.getContractSignedFlag());
respVO.setContractAmount(contractAmount); respVO.setContractAmount(contractAmount);
respVO.setFinalSettlementAmount(finalSettlementAmount); respVO.setFinalSettlementAmount(finalSettlementAmount);
// 历史字段名沿用 effectiveSettlementAmount当前业务含义为“合同产值不含增值税”。
respVO.setEffectiveSettlementAmount(contractAmountWithoutVat);
respVO.setComprehensivePlanningAmount(comprehensivePlanningAmount.setScale(2, RoundingMode.HALF_UP)); respVO.setComprehensivePlanningAmount(comprehensivePlanningAmount.setScale(2, RoundingMode.HALF_UP));
respVO.setSubcontractPlanningAmount(subcontractPlanningAmount.setScale(2, RoundingMode.HALF_UP)); respVO.setSubcontractPlanningAmount(subcontractPlanningAmount.setScale(2, RoundingMode.HALF_UP));
respVO.setSpecialSubcontractPlanningAmount(specialSubcontractPlanningAmount.setScale(2, RoundingMode.HALF_UP));
respVO.setSourceCoopSubcontractPlanningAmount(sourceCoopSubcontractPlanningAmount.setScale(2, RoundingMode.HALF_UP));
respVO.setComprehensiveSubcontractPlanningAmount(comprehensiveSubcontractPlanningAmount.setScale(2, RoundingMode.HALF_UP));
respVO.setMajorOutputValue(majorOutputValue.setScale(2, RoundingMode.HALF_UP)); respVO.setMajorOutputValue(majorOutputValue.setScale(2, RoundingMode.HALF_UP));
respVO.setMajorExpectedPerformance(majorExpectedPerformance); respVO.setMajorExpectedPerformance(majorExpectedPerformance.setScale(2, RoundingMode.HALF_UP));
respVO.setInnovationOutputRate(innovationOutputRate); respVO.setInnovationOutputRate(innovationOutputRate);
respVO.setInnovationOutputValue(innovationOutputValue); respVO.setInnovationOutputValue(innovationOutputValue);
respVO.setOtherCost(otherCost); respVO.setOtherCost(otherCost);
@@ -142,41 +250,66 @@ public class ProjectProfitServiceImpl implements ProjectProfitService {
return respVO; return respVO;
} }
private BigDecimal calculateMajorExpectedPerformance(List<ProjectPlanningDO> majorPlanningList) { private void fillSnapshots(ProjectProfitRespVO respVO) {
if (majorPlanningList == null || majorPlanningList.isEmpty()) { Map<String, ProjectCostMeasureSnapshotDO> snapshotMap = projectCostMeasureSnapshotMapper
return ZERO_AMOUNT; .selectListByProjectId(respVO.getProjectId())
} .stream()
List<Long> planningIds = majorPlanningList.stream().map(ProjectPlanningDO::getId).collect(Collectors.toList()); .collect(Collectors.toMap(ProjectCostMeasureSnapshotDO::getSnapshotType, item -> item, (a, b) -> b));
Map<Long, List<ProjectPlanningQuarterDO>> quarterMap = CollectionUtils.convertMultiMap( respVO.setBudgetSnapshot(toSnapshotRespVO(snapshotMap.get(ProjectCostMeasureSnapshotTypeEnum.BUDGET.getCode())));
projectPlanningQuarterMapper.selectListByPlanningIds(planningIds), ProjectPlanningQuarterDO::getPlanningId); respVO.setAccountingSnapshot(toSnapshotRespVO(snapshotMap.get(ProjectCostMeasureSnapshotTypeEnum.ACCOUNTING.getCode())));
Set<Integer> years = quarterMap.values().stream() respVO.setSettlementSnapshot(toSnapshotRespVO(snapshotMap.get(ProjectCostMeasureSnapshotTypeEnum.SETTLEMENT.getCode())));
.flatMap(Collection::stream) }
.map(ProjectPlanningQuarterDO::getDistributionYear)
.collect(Collectors.toSet());
Map<Integer, BigDecimal> yearKValueMap = yearKValueMapper.selectEnabledListByYears(years).stream()
.collect(Collectors.toMap(YearKValueDO::getKYear, item -> ratio(item.getKValue()), (a, b) -> b));
BigDecimal total = ZERO_AMOUNT; private ProjectCostMeasureSnapshotDO buildSnapshot(ProjectProfitRespVO profit, String snapshotType) {
for (ProjectPlanningDO planning : majorPlanningList) { ProjectCostMeasureSnapshotDO snapshot = new ProjectCostMeasureSnapshotDO();
BigDecimal assessmentOutputValue = amount(planning.getAssessmentOutputValue()); snapshot.setProjectId(profit.getProjectId());
Map<Integer, BigDecimal> yearRatioMap = quarterMap.getOrDefault(planning.getId(), Collections.emptyList()).stream() snapshot.setSnapshotType(snapshotType);
.collect(Collectors.groupingBy(ProjectPlanningQuarterDO::getDistributionYear, snapshot.setContractAmount(amount(profit.getContractAmount()));
Collectors.reducing(ZERO_RATIO, snapshot.setFinalSettlementAmount(amount(profit.getFinalSettlementAmount()));
item -> ratio(item.getDistributionRatio()), snapshot.setEffectiveSettlementAmount(amount(profit.getEffectiveSettlementAmount()));
BigDecimal::add))); snapshot.setComprehensivePlanningAmount(amount(profit.getComprehensivePlanningAmount()));
BigDecimal allocatedRatio = ZERO_RATIO; snapshot.setSubcontractPlanningAmount(amount(profit.getSubcontractPlanningAmount()));
for (Map.Entry<Integer, BigDecimal> entry : yearRatioMap.entrySet()) { snapshot.setSpecialSubcontractPlanningAmount(amount(profit.getSpecialSubcontractPlanningAmount()));
BigDecimal yearRatio = ratio(entry.getValue()); snapshot.setSourceCoopSubcontractPlanningAmount(amount(profit.getSourceCoopSubcontractPlanningAmount()));
allocatedRatio = allocatedRatio.add(yearRatio).setScale(4, RoundingMode.HALF_UP); snapshot.setComprehensiveSubcontractPlanningAmount(amount(profit.getComprehensiveSubcontractPlanningAmount()));
BigDecimal kValue = yearKValueMap.getOrDefault(entry.getKey(), DEFAULT_YEAR_K_VALUE); snapshot.setMajorOutputValue(amount(profit.getMajorOutputValue()));
total = total.add(multiplyAmount(assessmentOutputValue, yearRatio, kValue)); snapshot.setMajorExpectedPerformance(amount(profit.getMajorExpectedPerformance()));
} snapshot.setInnovationOutputRate(ratio(profit.getInnovationOutputRate()));
BigDecimal unallocatedRatio = ONE_RATIO.subtract(allocatedRatio).setScale(4, RoundingMode.HALF_UP); snapshot.setInnovationOutputValue(amount(profit.getInnovationOutputValue()));
if (unallocatedRatio.compareTo(ZERO_RATIO) > 0) { snapshot.setOtherCost(amount(profit.getOtherCost()));
total = total.add(multiplyAmount(assessmentOutputValue, unallocatedRatio, DEFAULT_YEAR_K_VALUE)); snapshot.setProfitLossValue(amount(profit.getProfitLossValue()));
} snapshot.setProfitLossRate(ratio(profit.getProfitLossRate()));
} return snapshot;
return total.setScale(2, RoundingMode.HALF_UP); }
private void copySnapshotValues(ProjectCostMeasureSnapshotDO source, ProjectCostMeasureSnapshotDO target) {
target.setContractAmount(amount(source.getContractAmount()));
target.setFinalSettlementAmount(amount(source.getFinalSettlementAmount()));
target.setEffectiveSettlementAmount(amount(source.getEffectiveSettlementAmount()));
target.setComprehensivePlanningAmount(amount(source.getComprehensivePlanningAmount()));
target.setSubcontractPlanningAmount(amount(source.getSubcontractPlanningAmount()));
target.setSpecialSubcontractPlanningAmount(amount(source.getSpecialSubcontractPlanningAmount()));
target.setSourceCoopSubcontractPlanningAmount(amount(source.getSourceCoopSubcontractPlanningAmount()));
target.setComprehensiveSubcontractPlanningAmount(amount(source.getComprehensiveSubcontractPlanningAmount()));
target.setMajorOutputValue(amount(source.getMajorOutputValue()));
target.setMajorExpectedPerformance(amount(source.getMajorExpectedPerformance()));
target.setInnovationOutputRate(ratio(source.getInnovationOutputRate()));
target.setInnovationOutputValue(amount(source.getInnovationOutputValue()));
target.setOtherCost(amount(source.getOtherCost()));
target.setProfitLossValue(amount(source.getProfitLossValue()));
target.setProfitLossRate(ratio(source.getProfitLossRate()));
}
private void fillActionInfo(ProjectCostMeasureSnapshotDO snapshot) {
Long userId = SecurityFrameworkUtils.getLoginUserId();
String nickname = SecurityFrameworkUtils.getLoginUserNickname();
snapshot.setActionUserId(userId);
snapshot.setActionUserName(nickname == null ? "" : nickname);
snapshot.setActionTime(LocalDateTime.now());
}
private ProjectProfitSnapshotRespVO toSnapshotRespVO(ProjectCostMeasureSnapshotDO snapshot) {
return snapshot == null ? null : BeanUtils.toBean(snapshot, ProjectProfitSnapshotRespVO.class);
} }
private ProjectDO validateProjectExists(Long projectId) { private ProjectDO validateProjectExists(Long projectId) {
@@ -195,6 +328,24 @@ public class ProjectProfitServiceImpl implements ProjectProfitService {
return value == null ? ZERO_RATIO : value.setScale(4, RoundingMode.HALF_UP); return value == null ? ZERO_RATIO : value.setScale(4, RoundingMode.HALF_UP);
} }
private BigDecimal taxExcludedAmount(BigDecimal amount) {
BigDecimal value = amount(amount);
if (value.compareTo(BigDecimal.ZERO) == 0) {
return ZERO_AMOUNT;
}
return value.divide(VAT_INCLUDED_DIVISOR, 2, RoundingMode.HALF_UP);
}
private BigDecimal getAssessmentCoefficient(String assessmentResult) {
if ("优秀".equals(assessmentResult)) {
return ASSESSMENT_COEFFICIENT_EXCELLENT;
}
if ("待改进".equals(assessmentResult)) {
return ASSESSMENT_COEFFICIENT_NEEDS_IMPROVEMENT;
}
return ASSESSMENT_COEFFICIENT_QUALIFIED;
}
private BigDecimal multiplyAmount(BigDecimal... values) { private BigDecimal multiplyAmount(BigDecimal... values) {
BigDecimal result = BigDecimal.ONE; BigDecimal result = BigDecimal.ONE;
for (BigDecimal value : values) { for (BigDecimal value : values) {

View File

@@ -18,6 +18,8 @@ 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.planningquarter.ProjectPlanningQuarterMapper;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.project.ProjectMapper; import cn.iocoder.lyzsys.module.tjt.dal.mysql.project.ProjectMapper;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.projectroleperson.ProjectRolePersonMapper; import cn.iocoder.lyzsys.module.tjt.dal.mysql.projectroleperson.ProjectRolePersonMapper;
import cn.iocoder.lyzsys.module.tjt.enums.OutputSplitBizConstants;
import cn.iocoder.lyzsys.module.tjt.enums.ProjectStatusEnum;
import cn.iocoder.lyzsys.module.tjt.service.employee.EmployeeService; import cn.iocoder.lyzsys.module.tjt.service.employee.EmployeeService;
import cn.iocoder.lyzsys.module.tjt.service.outputsplit.ProjectOutputSplitService; import cn.iocoder.lyzsys.module.tjt.service.outputsplit.ProjectOutputSplitService;
import cn.iocoder.lyzsys.module.tjt.service.planningguidedetail.ProjectPlanningGuideDetailService; import cn.iocoder.lyzsys.module.tjt.service.planningguidedetail.ProjectPlanningGuideDetailService;
@@ -37,6 +39,7 @@ import java.util.stream.Collectors;
import static cn.iocoder.lyzsys.framework.common.exception.util.ServiceExceptionUtil.exception; 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_NOT_EXISTS;
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_STATUS_INVALID;
/** /**
* 项目 Service 实现类 * 项目 Service 实现类
@@ -47,14 +50,12 @@ import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.PROJECT_NOT_
@Validated @Validated
public class ProjectServiceImpl implements ProjectService { public class ProjectServiceImpl implements ProjectService {
private static final String ROLE_CODE_PROJECT_MANAGER = "project_manager"; private static final String ROLE_CODE_PROJECT_MANAGER = OutputSplitBizConstants.ROLE_PROJECT_MANAGER;
private static final String ROLE_CODE_ENGINEERING_PRINCIPAL = "engineering_principal"; private static final String ROLE_CODE_ENGINEERING_PRINCIPAL = OutputSplitBizConstants.ROLE_ENGINEERING_PRINCIPAL;
private static final String ROLE_NAME_PROJECT_MANAGER = "项目经理"; private static final String STATUS_IN_PROGRESS = ProjectStatusEnum.IN_PROGRESS.getCode();
private static final String ROLE_NAME_ENGINEERING_PRINCIPAL = "工程负责人"; private static final String STATUS_COMPLETED = ProjectStatusEnum.COMPLETED.getCode();
private static final String STATUS_IN_PROGRESS = "进行中"; private static final String STATUS_PAUSED = ProjectStatusEnum.PAUSED.getCode();
private static final String STATUS_COMPLETED = "完成"; private static final String STATUS_TERMINATED = ProjectStatusEnum.TERMINATED.getCode();
private static final String STATUS_PAUSED = "暂停";
private static final String STATUS_TERMINATED = "中止";
@Resource @Resource
private ProjectMapper projectMapper; private ProjectMapper projectMapper;
@@ -141,14 +142,17 @@ public class ProjectServiceImpl implements ProjectService {
if (project.getProjectStatus() == null || project.getProjectStatus().trim().isEmpty()) { if (project.getProjectStatus() == null || project.getProjectStatus().trim().isEmpty()) {
project.setProjectStatus(dbProject == null ? STATUS_IN_PROGRESS : dbProject.getProjectStatus()); project.setProjectStatus(dbProject == null ? STATUS_IN_PROGRESS : dbProject.getProjectStatus());
} }
if (!ProjectStatusEnum.contains(project.getProjectStatus())) {
throw exception(PROJECT_STATUS_INVALID);
}
if (project.getArchiveFlag() == null) { if (project.getArchiveFlag() == null) {
project.setArchiveFlag(dbProject != null && Boolean.TRUE.equals(dbProject.getArchiveFlag())); project.setArchiveFlag(dbProject != null && Boolean.TRUE.equals(dbProject.getArchiveFlag()));
} }
if (project.getArchiveTime() == null && dbProject != null) { if (project.getArchiveTime() == null && dbProject != null) {
project.setArchiveTime(dbProject.getArchiveTime()); project.setArchiveTime(dbProject.getArchiveTime());
} }
if (project.getSortNo() == null) { if (project.getSortNo() == null && dbProject != null) {
project.setSortNo(dbProject == null || dbProject.getSortNo() == null ? 0 : dbProject.getSortNo()); project.setSortNo(dbProject.getSortNo());
} }
} }
@@ -203,10 +207,10 @@ public class ProjectServiceImpl implements ProjectService {
private String getRoleName(String roleCode) { private String getRoleName(String roleCode) {
if (Objects.equals(roleCode, ROLE_CODE_PROJECT_MANAGER)) { if (Objects.equals(roleCode, ROLE_CODE_PROJECT_MANAGER)) {
return ROLE_NAME_PROJECT_MANAGER; return OutputSplitBizConstants.getRoleName(roleCode);
} }
if (Objects.equals(roleCode, ROLE_CODE_ENGINEERING_PRINCIPAL)) { if (Objects.equals(roleCode, ROLE_CODE_ENGINEERING_PRINCIPAL)) {
return ROLE_NAME_ENGINEERING_PRINCIPAL; return OutputSplitBizConstants.getRoleName(roleCode);
} }
return roleCode; return roleCode;
} }
@@ -265,11 +269,8 @@ public class ProjectServiceImpl implements ProjectService {
Map<Long, List<ProjectPlanningQuarterDO>> quarterMap = CollectionUtils.convertMultiMap( Map<Long, List<ProjectPlanningQuarterDO>> quarterMap = CollectionUtils.convertMultiMap(
projectPlanningQuarterMapper.selectListByPlanningIds(planningIds), ProjectPlanningQuarterDO::getPlanningId); projectPlanningQuarterMapper.selectListByPlanningIds(planningIds), ProjectPlanningQuarterDO::getPlanningId);
for (ProjectPlanningDO planning : planningList) { for (ProjectPlanningDO planning : planningList) {
java.math.BigDecimal allocatedRatio = quarterMap.getOrDefault(planning.getId(), Collections.emptyList()).stream() java.math.BigDecimal allocatedRatio = resolveAllocatedRatio(
.map(ProjectPlanningQuarterDO::getDistributionRatio) planning, quarterMap.getOrDefault(planning.getId(), Collections.emptyList()));
.filter(Objects::nonNull)
.reduce(java.math.BigDecimal.ZERO, java.math.BigDecimal::add)
.setScale(4, java.math.RoundingMode.HALF_UP);
java.math.BigDecimal totalDistributionAmount = planning.getTotalDistributionAmount() == null java.math.BigDecimal totalDistributionAmount = planning.getTotalDistributionAmount() == null
? java.math.BigDecimal.ONE.setScale(4, java.math.RoundingMode.HALF_UP) ? java.math.BigDecimal.ONE.setScale(4, java.math.RoundingMode.HALF_UP)
: planning.getTotalDistributionAmount().setScale(4, java.math.RoundingMode.HALF_UP); : planning.getTotalDistributionAmount().setScale(4, java.math.RoundingMode.HALF_UP);
@@ -280,6 +281,39 @@ public class ProjectServiceImpl implements ProjectService {
return true; return true;
} }
private java.math.BigDecimal resolveAllocatedRatio(ProjectPlanningDO planning, List<ProjectPlanningQuarterDO> quarterList) {
if (quarterList == null || quarterList.isEmpty()) {
return java.math.BigDecimal.ZERO.setScale(4, java.math.RoundingMode.HALF_UP);
}
boolean hasGuideDetailQuarter = quarterList.stream().anyMatch(item -> item.getGuideDetailId() != null);
if (!hasGuideDetailQuarter) {
return quarterList.stream()
.map(ProjectPlanningQuarterDO::getDistributionRatio)
.filter(Objects::nonNull)
.reduce(java.math.BigDecimal.ZERO, java.math.BigDecimal::add)
.setScale(4, java.math.RoundingMode.HALF_UP);
}
java.math.BigDecimal totalDistributionAmount = planning.getTotalDistributionAmount() == null
? java.math.BigDecimal.ONE.setScale(4, java.math.RoundingMode.HALF_UP)
: planning.getTotalDistributionAmount().setScale(4, java.math.RoundingMode.HALF_UP);
java.math.BigDecimal baseAmount = amount(planning.getAssessmentOutputValue())
.multiply(totalDistributionAmount)
.setScale(2, java.math.RoundingMode.HALF_UP);
if (baseAmount.compareTo(java.math.BigDecimal.ZERO) == 0) {
return java.math.BigDecimal.ZERO.setScale(4, java.math.RoundingMode.HALF_UP);
}
java.math.BigDecimal allocatedAmount = quarterList.stream()
.map(ProjectPlanningQuarterDO::getDistributionAmount)
.map(this::amount)
.reduce(java.math.BigDecimal.ZERO.setScale(2, java.math.RoundingMode.HALF_UP), java.math.BigDecimal::add);
return allocatedAmount.divide(baseAmount, 4, java.math.RoundingMode.HALF_UP);
}
private java.math.BigDecimal amount(java.math.BigDecimal value) {
return value == null ? java.math.BigDecimal.ZERO.setScale(2, java.math.RoundingMode.HALF_UP)
: value.setScale(2, java.math.RoundingMode.HALF_UP);
}
private void deleteProjectDependencies(Collection<Long> projectIds) { private void deleteProjectDependencies(Collection<Long> projectIds) {
if (projectIds == null || projectIds.isEmpty()) { if (projectIds == null || projectIds.isEmpty()) {
return; return;

View File

@@ -1,11 +1,6 @@
package cn.iocoder.lyzsys.module.tjt.service.report; package cn.iocoder.lyzsys.module.tjt.service.report;
import cn.iocoder.lyzsys.module.tjt.controller.admin.report.vo.EmployeeOutputSummaryExportReqVO; import cn.iocoder.lyzsys.module.tjt.controller.admin.report.vo.*;
import cn.iocoder.lyzsys.module.tjt.controller.admin.report.vo.ProjectBudgetExportReqVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.report.vo.ProjectLeadQuarterOutputExportReqVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.report.vo.ProjectOverviewExportReqVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.report.vo.ProjectQuarterOutputExportReqVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.report.vo.SpecialtyPersonOutputExportReqVO;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
@@ -15,19 +10,31 @@ public interface ProjectOutputReportService {
void exportProjectBudgetExcel(HttpServletResponse response, ProjectBudgetExportReqVO reqVO) void exportProjectBudgetExcel(HttpServletResponse response, ProjectBudgetExportReqVO reqVO)
throws IOException; throws IOException;
ProjectBudgetPreviewRespVO getProjectBudgetPreview(ProjectBudgetExportReqVO reqVO);
void exportProjectQuarterOutputExcel(HttpServletResponse response, ProjectQuarterOutputExportReqVO reqVO) void exportProjectQuarterOutputExcel(HttpServletResponse response, ProjectQuarterOutputExportReqVO reqVO)
throws IOException; throws IOException;
ProjectQuarterOutputPreviewRespVO getProjectQuarterOutputPreview(ProjectQuarterOutputExportReqVO reqVO);
void exportProjectLeadQuarterOutputExcel(HttpServletResponse response, void exportProjectLeadQuarterOutputExcel(HttpServletResponse response,
ProjectLeadQuarterOutputExportReqVO reqVO) ProjectLeadQuarterOutputExportReqVO reqVO)
throws IOException; throws IOException;
ProjectLeadQuarterOutputPreviewRespVO getProjectLeadQuarterOutputPreview(ProjectLeadQuarterOutputExportReqVO reqVO);
void exportSpecialtyPersonOutputExcel(HttpServletResponse response, SpecialtyPersonOutputExportReqVO reqVO) void exportSpecialtyPersonOutputExcel(HttpServletResponse response, SpecialtyPersonOutputExportReqVO reqVO)
throws IOException; throws IOException;
SpecialtyPersonOutputPreviewRespVO getSpecialtyPersonOutputPreview(SpecialtyPersonOutputPreviewReqVO reqVO);
ProjectOverviewPreviewRespVO getProjectOverviewPreview(ProjectOverviewExportReqVO reqVO);
void exportProjectOverviewExcel(HttpServletResponse response, ProjectOverviewExportReqVO reqVO) void exportProjectOverviewExcel(HttpServletResponse response, ProjectOverviewExportReqVO reqVO)
throws IOException; throws IOException;
EmployeeOutputSummaryPreviewRespVO getEmployeeOutputSummaryPreview(EmployeeOutputSummaryExportReqVO reqVO);
void exportEmployeeOutputSummaryExcel(HttpServletResponse response, EmployeeOutputSummaryExportReqVO reqVO) void exportEmployeeOutputSummaryExcel(HttpServletResponse response, EmployeeOutputSummaryExportReqVO reqVO)
throws IOException; throws IOException;

View File

@@ -24,7 +24,7 @@ public class EmployeeOutputSummaryExcelBuilder extends AbstractProjectOutputExce
private static final String TITLE_PREFIX = "7.1.6 "; private static final String TITLE_PREFIX = "7.1.6 ";
private static final String TITLE_SUFFIX = " 年设计中心员工个人考核产值汇总,全公司产值人员汇总表"; private static final String TITLE_SUFFIX = " 年设计中心员工个人考核产值汇总,全公司产值人员汇总表";
private static final String SUBTITLE_SUFFIX = " 年设计中心员工个人考核产值汇总(单位:万元)"; private static final String SUBTITLE_SUFFIX = " 年设计中心员工个人考核产值汇总(单位:万元)";
private static final int LAST_COL = 12; private static final int LAST_COL = 13;
private static final int DETAIL_START_ROW_NUM = 4; private static final int DETAIL_START_ROW_NUM = 4;
public Workbook build(ExportData data) { public Workbook build(ExportData data) {
@@ -36,7 +36,7 @@ public class EmployeeOutputSummaryExcelBuilder extends AbstractProjectOutputExce
private void buildSheet(Workbook workbook, ExportData data) { private void buildSheet(Workbook workbook, ExportData data) {
Sheet sheet = createSheet(workbook, SHEET_NAME, SHEET_NAME); Sheet sheet = createSheet(workbook, SHEET_NAME, SHEET_NAME);
setColumnWidths(sheet, 8, 14, 12, 12, 12, 12, 12, 14, 14, 18, 14, 14, 14); setColumnWidths(sheet, 8, 16, 14, 12, 12, 12, 12, 12, 14, 14, 18, 14, 14, 14);
CellStyle subtitleStyle = createDerivedStyle(workbook, createInfoStyle(workbook), CellStyle subtitleStyle = createDerivedStyle(workbook, createInfoStyle(workbook),
null, HorizontalAlignment.CENTER, true, (short) 11); null, HorizontalAlignment.CENTER, true, (short) 11);
@@ -80,7 +80,7 @@ public class EmployeeOutputSummaryExcelBuilder extends AbstractProjectOutputExce
private int writeHeaderRow(Sheet sheet, int rowIndex, CellStyle style) { private int writeHeaderRow(Sheet sheet, int rowIndex, CellStyle style) {
writeRow(sheet, rowIndex, style, writeRow(sheet, rowIndex, style,
"序号", "姓名", "第一季度", "第二季度", "第三季度", "第四季度", "年度合计", "序号", "专业所", "姓名", "第一季度", "第二季度", "第三季度", "第四季度", "年度合计",
"所长 / BIM 考核产值", "年度考核产值合计", "1~12 月份预计发生成本(含预计精神文明奖)", "所长 / BIM 考核产值", "年度考核产值合计", "1~12 月份预计发生成本(含预计精神文明奖)",
"基本考核产值", "剩余产值", "预估年底绩效"); "基本考核产值", "剩余产值", "预估年底绩效");
return rowIndex + 1; return rowIndex + 1;
@@ -92,19 +92,20 @@ public class EmployeeOutputSummaryExcelBuilder extends AbstractProjectOutputExce
Row row = sheet.createRow(rowIndex); Row row = sheet.createRow(rowIndex);
int excelRowNum = rowIndex + 1; int excelRowNum = rowIndex + 1;
setText(row, 0, rowData == null || rowData.getSerialNo() == null ? "" : rowData.getSerialNo(), cellStyle); setText(row, 0, rowData == null || rowData.getSerialNo() == null ? "" : rowData.getSerialNo(), cellStyle);
setText(row, 1, rowData == null ? "" : safeText(rowData.getEmployeeName()), leftCellStyle); setText(row, 1, rowData == null ? "" : safeText(rowData.getOfficeName()), leftCellStyle);
setNumericCell(row, 2, rowData == null ? null : rowData.getQuarterOneAmount(), amountStyle); setText(row, 2, rowData == null ? "" : safeText(rowData.getEmployeeName()), leftCellStyle);
setNumericCell(row, 3, rowData == null ? null : rowData.getQuarterTwoAmount(), amountStyle); setNumericCell(row, 3, rowData == null ? null : rowData.getQuarterOneAmount(), amountStyle);
setNumericCell(row, 4, rowData == null ? null : rowData.getQuarterThreeAmount(), amountStyle); setNumericCell(row, 4, rowData == null ? null : rowData.getQuarterTwoAmount(), amountStyle);
setNumericCell(row, 5, rowData == null ? null : rowData.getQuarterFourAmount(), amountStyle); setNumericCell(row, 5, rowData == null ? null : rowData.getQuarterThreeAmount(), amountStyle);
setNumericCell(row, 6, rowData == null ? null : rowData.getAnnualTotalAmount(), amountStyle); setNumericCell(row, 6, rowData == null ? null : rowData.getQuarterFourAmount(), amountStyle);
setNumericCell(row, 7, rowData == null ? null : rowData.getOfficeLeaderOrBimAmount(), amountStyle); setNumericCell(row, 7, rowData == null ? null : rowData.getAnnualTotalAmount(), amountStyle);
setNumericCell(row, 8, rowData == null ? null : rowData.getTotalAssessmentOutputAmount(), amountStyle); setNumericCell(row, 8, rowData == null ? null : rowData.getOfficeLeaderOrBimAmount(), amountStyle);
setNumericCell(row, 9, rowData == null ? null : rowData.getExpectedCostAmount(), amountStyle); setNumericCell(row, 9, rowData == null ? null : rowData.getTotalAssessmentOutputAmount(), amountStyle);
setNumericCell(row, 10, rowData == null ? null : rowData.getExpectedCostAmount(), amountStyle);
setFormulaCell(row, 10, buildBasicAssessmentFormula(excelRowNum, data), formulaStyle); setFormulaCell(row, 11, buildBasicAssessmentFormula(excelRowNum, data), formulaStyle);
setFormulaCell(row, 11, buildRemainingOutputFormula(excelRowNum), formulaStyle); setFormulaCell(row, 12, buildRemainingOutputFormula(excelRowNum), formulaStyle);
setFormulaCell(row, 12, buildPerformanceFormula(excelRowNum, data), formulaStyle); setFormulaCell(row, 13, buildPerformanceFormula(excelRowNum, data), formulaStyle);
} }
private void writeTotalRow(Sheet sheet, int rowIndex, List<EmployeeOutputSummaryExcelRespVO> rows, ExportData data, private void writeTotalRow(Sheet sheet, int rowIndex, List<EmployeeOutputSummaryExcelRespVO> rows, ExportData data,
@@ -115,8 +116,9 @@ public class EmployeeOutputSummaryExcelBuilder extends AbstractProjectOutputExce
int detailEndRowNum = DETAIL_START_ROW_NUM + rows.size() - 1; int detailEndRowNum = DETAIL_START_ROW_NUM + rows.size() - 1;
setText(row, 0, "", totalCellStyle); setText(row, 0, "", totalCellStyle);
setText(row, 1, "合计", totalLeftCellStyle); setText(row, 1, "", totalLeftCellStyle);
for (int col = 2; col <= LAST_COL; col++) { setText(row, 2, "合计", totalLeftCellStyle);
for (int col = 3; col <= LAST_COL; col++) {
if (rows.isEmpty()) { if (rows.isEmpty()) {
setNumericCell(row, col, BigDecimal.ZERO, totalStyle); setNumericCell(row, col, BigDecimal.ZERO, totalStyle);
continue; continue;
@@ -126,9 +128,9 @@ public class EmployeeOutputSummaryExcelBuilder extends AbstractProjectOutputExce
} }
// Ensure total-row formulas survive even if Excel recalculation is disabled. // Ensure total-row formulas survive even if Excel recalculation is disabled.
if (!rows.isEmpty()) { if (!rows.isEmpty()) {
row.getCell(10).setCellFormula(buildTotalBasicAssessmentFormula(totalExcelRowNum)); row.getCell(11).setCellFormula(buildTotalBasicAssessmentFormula(totalExcelRowNum));
row.getCell(11).setCellFormula(buildTotalRemainingOutputFormula(totalExcelRowNum)); row.getCell(12).setCellFormula(buildTotalRemainingOutputFormula(totalExcelRowNum));
row.getCell(12).setCellFormula(buildTotalPerformanceFormula(totalExcelRowNum, data)); row.getCell(13).setCellFormula(buildTotalPerformanceFormula(totalExcelRowNum, data));
} }
} }
@@ -137,11 +139,11 @@ public class EmployeeOutputSummaryExcelBuilder extends AbstractProjectOutputExce
if (kValue.compareTo(BigDecimal.ZERO) <= 0) { if (kValue.compareTo(BigDecimal.ZERO) <= 0) {
return "0"; return "0";
} }
return "ROUND(J" + excelRowNum + "/" + kValue.stripTrailingZeros().toPlainString() + ",2)"; return "ROUND(K" + excelRowNum + "/" + kValue.stripTrailingZeros().toPlainString() + ",2)";
} }
private String buildRemainingOutputFormula(int excelRowNum) { private String buildRemainingOutputFormula(int excelRowNum) {
return "ROUND(I" + excelRowNum + "-K" + excelRowNum + ",2)"; return "ROUND(J" + excelRowNum + "-L" + excelRowNum + ",2)";
} }
private String buildPerformanceFormula(int excelRowNum, ExportData data) { private String buildPerformanceFormula(int excelRowNum, ExportData data) {
@@ -149,21 +151,21 @@ public class EmployeeOutputSummaryExcelBuilder extends AbstractProjectOutputExce
if (kValue.compareTo(BigDecimal.ZERO) <= 0) { if (kValue.compareTo(BigDecimal.ZERO) <= 0) {
return "0"; return "0";
} }
return "ROUND(L" + excelRowNum + "*" + kValue.stripTrailingZeros().toPlainString() + ",2)"; return "ROUND(M" + excelRowNum + "*" + kValue.stripTrailingZeros().toPlainString() + ",2)";
} }
private String buildTotalBasicAssessmentFormula(int excelRowNum) { private String buildTotalBasicAssessmentFormula(int excelRowNum) {
return "SUM(K" + DETAIL_START_ROW_NUM + ":K" + (excelRowNum - 1) + ")";
}
private String buildTotalRemainingOutputFormula(int excelRowNum) {
return "SUM(L" + DETAIL_START_ROW_NUM + ":L" + (excelRowNum - 1) + ")"; return "SUM(L" + DETAIL_START_ROW_NUM + ":L" + (excelRowNum - 1) + ")";
} }
private String buildTotalPerformanceFormula(int excelRowNum, ExportData data) { private String buildTotalRemainingOutputFormula(int excelRowNum) {
return "SUM(M" + DETAIL_START_ROW_NUM + ":M" + (excelRowNum - 1) + ")"; return "SUM(M" + DETAIL_START_ROW_NUM + ":M" + (excelRowNum - 1) + ")";
} }
private String buildTotalPerformanceFormula(int excelRowNum, ExportData data) {
return "SUM(N" + DETAIL_START_ROW_NUM + ":N" + (excelRowNum - 1) + ")";
}
private String safeYear(ExportData data) { private String safeYear(ExportData data) {
return data == null || data.getYear() == null ? "" : String.valueOf(data.getYear()); return data == null || data.getYear() == null ? "" : String.valueOf(data.getYear());
} }

View File

@@ -35,7 +35,7 @@ public class ProjectBudgetExcelBuilder extends AbstractProjectOutputExcelBuilder
private void buildBudgetSheet(Workbook workbook, ExportData data) { private void buildBudgetSheet(Workbook workbook, ExportData data) {
Sheet sheet = createSheet(workbook, BUDGET_SHEET_NAME, BUDGET_SHEET_FALLBACK_NAME); Sheet sheet = createSheet(workbook, BUDGET_SHEET_NAME, BUDGET_SHEET_FALLBACK_NAME);
setColumnWidths(sheet, 16, 14, 18, 16, 18, 14, 12, 12, 12, 18, 12, 14, 16); setColumnWidths(sheet, 16, 14, 22, 16, 18, 14, 12, 12, 12, 18, 12, 14, 16);
CellStyle titleStyle = createTitleStyle(workbook); CellStyle titleStyle = createTitleStyle(workbook);
CellStyle infoStyle = createInfoStyle(workbook); CellStyle infoStyle = createInfoStyle(workbook);
@@ -110,7 +110,7 @@ public class ProjectBudgetExcelBuilder extends AbstractProjectOutputExcelBuilder
setMergedRegionText(sheet, firstRow + 1, firstRow + 1, 7, 9, "调整系数", headerStyle); setMergedRegionText(sheet, firstRow + 1, firstRow + 1, 7, 9, "调整系数", headerStyle);
writeRow(sheet, firstRow + 2, headerStyle, (Object[]) new String[]{ writeRow(sheet, firstRow + 2, headerStyle, (Object[]) new String[]{
"规划内容", "设计部位", "建筑类型", "", "", "栋数 / 户型数", "规划内容", "设计部位", "设计内容/设计类型", "", "", "栋数 / 户型数",
"套图系数", "规模系数", "修改系数", "复杂系数 / 复杂等级", "", "", "" "套图系数", "规模系数", "修改系数", "复杂系数 / 复杂等级", "", "", ""
}); });
return rowIndex + 3; return rowIndex + 3;

View File

@@ -21,14 +21,16 @@ public class ProjectLeadQuarterOutputExcelBuilder extends AbstractProjectOutputE
private static final String SHEET1_NAME = "工作量分配"; private static final String SHEET1_NAME = "工作量分配";
private static final String SHEET2_NAME = "季度考核产值"; private static final String SHEET2_NAME = "季度考核产值";
private static final String SHEET1_TITLE = "项目经理/专业负责人人员工作量分配"; private static final String SHEET1_TITLE = "项目经理/专业负责人人员工作量分配";
private static final String SHEET2_TITLE = "项目经理/工程负责人年度/季度项目考核产值"; private static final String SHEET2_TITLE = "工程负责人年度";
private static final String DEFAULT_PROJECT_MANAGER_HEADER = "项目经理人员"; private static final String DEFAULT_PROJECT_MANAGER_HEADER = "项目经理人员";
private static final String DEFAULT_ENGINEERING_HEADER = "工程负责人人员"; private static final String DEFAULT_ENGINEERING_HEADER = "工程负责人人员";
private static final String DEFAULT_CENTER_SIGNER = "设计中心相关负责人(签名):"; private static final String DEFAULT_CENTER_SIGNER = "设计中心相关负责人(签名):";
private static final String DEFAULT_PROJECT_SIGNER = "项目经理/工程负责人(签名):"; private static final String DEFAULT_PROJECT_SIGNER = "项目经理/工程负责人(签名):";
private static final List<String> OUTPUT_TYPE_ORDER = Arrays.asList( private static final List<String> OUTPUT_TYPE_ORDER = Arrays.asList(
"六大专业考核产值", "六大专业考核产值",
"分包产值", "分包-专业所产值",
"专项分包-源头合作分包产值",
"专项分包-综合所产值",
"内部协作产值", "内部协作产值",
"其他产值" "其他产值"
); );

View File

@@ -22,8 +22,8 @@ import java.util.Map;
@Component @Component
public class ProjectQuarterOutputExcelBuilder extends AbstractProjectOutputExcelBuilder { public class ProjectQuarterOutputExcelBuilder extends AbstractProjectOutputExcelBuilder {
private static final String SHEET1_NAME = "专业间项目考核产值年度季度计取"; private static final String SHEET1_NAME = "专业间年度";
private static final String SHEET1_FALLBACK_NAME = "项目级年度季度计取"; private static final String SHEET1_FALLBACK_NAME = "专业间年度";
private static final String SHEET2_NAME = "专业维度统计表"; private static final String SHEET2_NAME = "专业维度统计表";
private static final String SHEET2_FALLBACK_NAME = "专业维度统计"; private static final String SHEET2_FALLBACK_NAME = "专业维度统计";
@@ -36,14 +36,18 @@ public class ProjectQuarterOutputExcelBuilder extends AbstractProjectOutputExcel
private static final List<String> OUTPUT_TYPE_ORDER = Arrays.asList( private static final List<String> OUTPUT_TYPE_ORDER = Arrays.asList(
"六大专业考核产值", "六大专业考核产值",
"分包产值", "分包-专业所产值",
"专项分包-源头合作分包产值",
"专项分包-综合所产值",
"内部协作产值", "内部协作产值",
"其他产值" "其他产值"
); );
private static final List<String> FIXED_OUTPUT_TYPES = Arrays.asList( private static final List<String> FIXED_OUTPUT_TYPES = Arrays.asList(
"六大专业考核产值", "六大专业考核产值",
"分包产值", "分包-专业所产值",
"专项分包-源头合作分包产值",
"专项分包-综合所产值",
"内部协作产值" "内部协作产值"
); );

View File

@@ -534,12 +534,18 @@ public class SpecialtyPersonOutputExcelBuilder extends AbstractProjectOutputExce
if (Objects.equals(current, "六大专业考核产值")) { if (Objects.equals(current, "六大专业考核产值")) {
return 1; return 1;
} }
if (Objects.equals(current, "分包产值")) { if (Objects.equals(current, "分包-专业所产值")) {
return 2; return 2;
} }
if (Objects.equals(current, "内部协作产值")) { if (Objects.equals(current, "专项分包-源头合作分包产值")) {
return 3; return 3;
} }
if (Objects.equals(current, "专项分包-综合所产值")) {
return 4;
}
if (Objects.equals(current, "内部协作产值")) {
return 5;
}
return 9; return 9;
} }
@@ -637,10 +643,15 @@ public class SpecialtyPersonOutputExcelBuilder extends AbstractProjectOutputExce
@Data @Data
public static class PersonAmountValue { public static class PersonAmountValue {
private BigDecimal quarterOneRatio;
private BigDecimal quarterOneAmountWan; private BigDecimal quarterOneAmountWan;
private BigDecimal quarterTwoRatio;
private BigDecimal quarterTwoAmountWan; private BigDecimal quarterTwoAmountWan;
private BigDecimal quarterThreeRatio;
private BigDecimal quarterThreeAmountWan; private BigDecimal quarterThreeAmountWan;
private BigDecimal quarterFourRatio;
private BigDecimal quarterFourAmountWan; private BigDecimal quarterFourAmountWan;
private BigDecimal yearTotalRatio;
private BigDecimal yearTotalAmountWan; private BigDecimal yearTotalAmountWan;
} }

View File

@@ -3,7 +3,9 @@ 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.SpecialtyRoleSplitBatchSaveReqVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.specialtyrolesplit.vo.SpecialtyRoleSplitRespVO; import cn.iocoder.lyzsys.module.tjt.controller.admin.specialtyrolesplit.vo.SpecialtyRoleSplitRespVO;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 页面5角色比例 Service 接口 * 页面5角色比例 Service 接口
@@ -14,6 +16,12 @@ public interface SpecialtyRoleSplitService {
List<SpecialtyRoleSplitRespVO> getSpecialtyRoleSplitListByPlanningId(Long planningId); List<SpecialtyRoleSplitRespVO> getSpecialtyRoleSplitListByPlanningId(Long planningId);
Map<Long, List<SpecialtyRoleSplitRespVO>> getSpecialtyRoleSplitListMapByPlanningIds(Collection<Long> planningIds);
Map<Long, List<SpecialtyRoleSplitRespVO>> getExistingSpecialtyRoleSplitListMapByPlanningIds(Collection<Long> planningIds);
Map<Long, List<SpecialtyRoleSplitRespVO>> getReadonlySpecialtyRoleSplitListMapByPlanningIds(Collection<Long> planningIds);
void saveSpecialtyRoleSplitBatch(SpecialtyRoleSplitBatchSaveReqVO reqVO); void saveSpecialtyRoleSplitBatch(SpecialtyRoleSplitBatchSaveReqVO reqVO);
void deleteByOutputSplitId(Long outputSplitId); void deleteByOutputSplitId(Long outputSplitId);

View File

@@ -1,48 +1,35 @@
package cn.iocoder.lyzsys.module.tjt.service.specialtyrolesplit; package cn.iocoder.lyzsys.module.tjt.service.specialtyrolesplit;
import cn.iocoder.lyzsys.framework.common.util.json.JsonUtils;
import cn.iocoder.lyzsys.framework.common.util.object.BeanUtils; 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.*;
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.employee.EmployeeDO; import cn.iocoder.lyzsys.module.tjt.dal.dataobject.employee.EmployeeDO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.outputsplit.ProjectOutputSplitDO; 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.planning.ProjectPlanningDO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.project.ProjectDO; import cn.iocoder.lyzsys.module.tjt.dal.dataobject.project.ProjectDO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.projectroleperson.ProjectRolePersonDO; import cn.iocoder.lyzsys.module.tjt.dal.dataobject.projectroleperson.ProjectRolePersonDO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.specialtyrolesplit.SpecialtyRoleSplitDO; import cn.iocoder.lyzsys.module.tjt.dal.dataobject.specialtyrolesplit.SpecialtyRoleSplitDO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.specialtyrolesplitperson.SpecialtyRoleSplitPersonDO;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.planning.ProjectPlanningMapper; 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.project.ProjectMapper;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.projectroleperson.ProjectRolePersonMapper; import cn.iocoder.lyzsys.module.tjt.dal.mysql.projectroleperson.ProjectRolePersonMapper;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.specialtyrolesplit.SpecialtyRoleSplitMapper; import cn.iocoder.lyzsys.module.tjt.dal.mysql.specialtyrolesplit.SpecialtyRoleSplitMapper;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.specialtyrolesplitperson.SpecialtyRoleSplitPersonMapper;
import cn.iocoder.lyzsys.module.tjt.enums.OutputSplitBizConstants; import cn.iocoder.lyzsys.module.tjt.enums.OutputSplitBizConstants;
import cn.iocoder.lyzsys.module.tjt.service.employee.EmployeeService; import cn.iocoder.lyzsys.module.tjt.service.employee.EmployeeService;
import cn.iocoder.lyzsys.module.tjt.service.outputsplit.ProjectOutputSplitDefaults;
import cn.iocoder.lyzsys.module.tjt.service.outputsplit.ProjectOutputSplitService; import cn.iocoder.lyzsys.module.tjt.service.outputsplit.ProjectOutputSplitService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static cn.iocoder.lyzsys.framework.common.exception.util.ServiceExceptionUtil.exception; 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.*;
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;
@Service @Service
@Validated @Validated
@@ -58,6 +45,8 @@ public class SpecialtyRoleSplitServiceImpl implements SpecialtyRoleSplitService
@Resource @Resource
private SpecialtyRoleSplitMapper specialtyRoleSplitMapper; private SpecialtyRoleSplitMapper specialtyRoleSplitMapper;
@Resource @Resource
private SpecialtyRoleSplitPersonMapper specialtyRoleSplitPersonMapper;
@Resource
private ProjectOutputSplitService projectOutputSplitService; private ProjectOutputSplitService projectOutputSplitService;
@Resource @Resource
private ProjectPlanningMapper projectPlanningMapper; private ProjectPlanningMapper projectPlanningMapper;
@@ -71,28 +60,141 @@ public class SpecialtyRoleSplitServiceImpl implements SpecialtyRoleSplitService
@Override @Override
public List<SpecialtyRoleSplitRespVO> getSpecialtyRoleSplitListByPlanningId(Long planningId) { public List<SpecialtyRoleSplitRespVO> getSpecialtyRoleSplitListByPlanningId(Long planningId) {
ProjectPlanningDO planning = validatePlanningExists(planningId); ProjectPlanningDO planning = validatePlanningExists(planningId);
ProjectDO project = validateProjectExists(planning.getProjectId()); validateProjectExists(planning.getProjectId());
ProjectOutputSplitDO outputSplit = projectOutputSplitService.getOrCreateProjectOutputSplit(planningId); return getSpecialtyRoleSplitListMapByPlanningIds(Collections.singletonList(planningId))
List<SpecialtyRoleSplitDO> dbList = specialtyRoleSplitMapper.selectListByOutputSplitId(outputSplit.getId()); .getOrDefault(planningId, Collections.emptyList());
Map<String, SpecialtyRoleSplitDO> dbMap = dbList.stream().collect(Collectors.toMap( }
item -> item.getSpecialtyCode() + ":" + item.getRoleCode(), item -> item, (a, b) -> b));
Map<String, List<ProjectRolePersonDO>> projectRolePersonMap = projectRolePersonMapper
.selectListByProjectId(project.getId()).stream()
.collect(Collectors.groupingBy(ProjectRolePersonDO::getRoleCode, LinkedHashMap::new, Collectors.toList()));
@Override
public Map<Long, List<SpecialtyRoleSplitRespVO>> getSpecialtyRoleSplitListMapByPlanningIds(Collection<Long> planningIds) {
return getSpecialtyRoleSplitListMapByPlanningIds(planningIds, true, false);
}
@Override
public Map<Long, List<SpecialtyRoleSplitRespVO>> getExistingSpecialtyRoleSplitListMapByPlanningIds(Collection<Long> planningIds) {
return getSpecialtyRoleSplitListMapByPlanningIds(planningIds, false, false);
}
@Override
public Map<Long, List<SpecialtyRoleSplitRespVO>> getReadonlySpecialtyRoleSplitListMapByPlanningIds(Collection<Long> planningIds) {
return getSpecialtyRoleSplitListMapByPlanningIds(planningIds, false, true);
}
private Map<Long, List<SpecialtyRoleSplitRespVO>> getSpecialtyRoleSplitListMapByPlanningIds(
Collection<Long> planningIds, boolean createMissingOutputSplit, boolean defaultMissingOutputSplit) {
if (planningIds == null || planningIds.isEmpty()) {
return Collections.emptyMap();
}
List<Long> normalizedPlanningIds = planningIds.stream()
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());
if (normalizedPlanningIds.isEmpty()) {
return Collections.emptyMap();
}
Map<Long, ProjectPlanningDO> planningMap = projectPlanningMapper.selectBatchIds(normalizedPlanningIds).stream()
.filter(Objects::nonNull)
.collect(Collectors.toMap(ProjectPlanningDO::getId, item -> item, (a, b) -> a, LinkedHashMap::new));
if (planningMap.isEmpty()) {
return Collections.emptyMap();
}
Set<Long> projectIds = planningMap.values().stream()
.map(ProjectPlanningDO::getProjectId)
.filter(Objects::nonNull)
.collect(Collectors.toCollection(LinkedHashSet::new));
Map<Long, ProjectDO> projectMap = projectIds.isEmpty()
? Collections.emptyMap()
: projectMapper.selectBatchIds(projectIds).stream()
.filter(Objects::nonNull)
.collect(Collectors.toMap(ProjectDO::getId, item -> item, (a, b) -> a, LinkedHashMap::new));
Map<Long, ProjectOutputSplitDO> outputSplitMap = new LinkedHashMap<>(
projectOutputSplitService.getProjectOutputSplitMap(planningMap.keySet()));
if (createMissingOutputSplit) {
for (ProjectPlanningDO planning : planningMap.values()) {
if (!outputSplitMap.containsKey(planning.getId())) {
outputSplitMap.put(planning.getId(),
projectOutputSplitService.getOrCreateProjectOutputSplit(planning.getId()));
}
}
} else if (defaultMissingOutputSplit) {
for (ProjectPlanningDO planning : planningMap.values()) {
if (!outputSplitMap.containsKey(planning.getId())) {
outputSplitMap.put(planning.getId(), ProjectOutputSplitDefaults.build(planning));
}
}
}
List<Long> outputSplitIds = outputSplitMap.values().stream()
.filter(Objects::nonNull)
.map(ProjectOutputSplitDO::getId)
.filter(Objects::nonNull)
.collect(Collectors.toList());
Map<Long, List<SpecialtyRoleSplitDO>> roleSplitMap = specialtyRoleSplitMapper
.selectListByOutputSplitIds(outputSplitIds).stream()
.collect(Collectors.groupingBy(SpecialtyRoleSplitDO::getOutputSplitId,
LinkedHashMap::new, Collectors.toList()));
List<Long> roleSplitIds = roleSplitMap.values().stream()
.flatMap(Collection::stream)
.map(SpecialtyRoleSplitDO::getId)
.filter(Objects::nonNull)
.collect(Collectors.toList());
Map<Long, List<SpecialtyRoleSplitPersonDO>> personMap = specialtyRoleSplitPersonMapper
.selectListByRoleSplitIds(roleSplitIds)
.stream()
.collect(Collectors.groupingBy(SpecialtyRoleSplitPersonDO::getRoleSplitId,
LinkedHashMap::new, Collectors.toList()));
Map<Long, Map<String, List<ProjectRolePersonDO>>> projectRolePersonMap = projectRolePersonMapper
.selectListByProjectIds(projectIds).stream()
.collect(Collectors.groupingBy(ProjectRolePersonDO::getProjectId, LinkedHashMap::new,
Collectors.groupingBy(ProjectRolePersonDO::getRoleCode, LinkedHashMap::new, Collectors.toList())));
Map<Long, List<SpecialtyRoleSplitRespVO>> result = new LinkedHashMap<>();
for (Long planningId : normalizedPlanningIds) {
ProjectPlanningDO planning = planningMap.get(planningId);
if (planning == null) {
continue;
}
ProjectOutputSplitDO outputSplit = outputSplitMap.get(planningId);
if (outputSplit == null) {
continue;
}
ProjectDO project = projectMap.get(planning.getProjectId());
List<SpecialtyRoleSplitDO> roleList = roleSplitMap.getOrDefault(outputSplit.getId(), Collections.emptyList());
Map<String, List<ProjectRolePersonDO>> projectPersons = projectRolePersonMap
.getOrDefault(planning.getProjectId(), Collections.emptyMap());
result.put(planningId, buildRoleSplitRespList(planning, project, outputSplit, roleList, projectPersons, personMap));
}
return result;
}
private List<SpecialtyRoleSplitRespVO> buildRoleSplitRespList(ProjectPlanningDO planning,
ProjectDO project,
ProjectOutputSplitDO outputSplit,
List<SpecialtyRoleSplitDO> dbList,
Map<String, List<ProjectRolePersonDO>> projectRolePersonMap,
Map<Long, List<SpecialtyRoleSplitPersonDO>> personMap) {
List<SpecialtyRoleSplitDO> safeDbList = dbList == null ? Collections.emptyList() : dbList;
Map<String, SpecialtyRoleSplitDO> dbMap = safeDbList.stream().collect(Collectors.toMap(
item -> item.getSpecialtyCode() + ":" + item.getRoleCode(), item -> item, (a, b) -> b));
List<SpecialtyRoleSplitRespVO> result = new ArrayList<>(); List<SpecialtyRoleSplitRespVO> result = new ArrayList<>();
BigDecimal assessmentOutputValue = planning.getAssessmentOutputValue(); BigDecimal assessmentOutputValue = planning.getAssessmentOutputValue();
boolean useDefaultProjectLeadRoleRatio = shouldUseDefaultProjectLeadRoleRatio(dbMap, projectRolePersonMap);
for (OutputSplitBizConstants.SpecialtyItem specialtyItem : OutputSplitBizConstants.ASSIGNMENT_SPECIALTY_ITEMS) { for (OutputSplitBizConstants.SpecialtyItem specialtyItem : OutputSplitBizConstants.ASSIGNMENT_SPECIALTY_ITEMS) {
BigDecimal specialtyAmount = getSpecialtyAmount(outputSplit, assessmentOutputValue, specialtyItem.getCode()); BigDecimal specialtyAmount = getSpecialtyAmount(outputSplit, assessmentOutputValue, specialtyItem.getCode());
Map<String, BigDecimal> defaultRoleRatioMap = buildDefaultRoleRatioMap( Map<String, BigDecimal> defaultRoleRatioMap = buildDefaultRoleRatioMap(
specialtyItem.getCode(), projectRolePersonMap); specialtyItem.getCode(), projectRolePersonMap);
for (OutputSplitBizConstants.RoleItem roleItem : OutputSplitBizConstants.getRoleItems(specialtyItem.getCode())) { for (OutputSplitBizConstants.RoleItem roleItem : OutputSplitBizConstants.getRoleItems(specialtyItem.getCode())) {
SpecialtyRoleSplitDO dbItem = dbMap.get(specialtyItem.getCode() + ":" + roleItem.getCode()); SpecialtyRoleSplitDO dbItem = dbMap.get(specialtyItem.getCode() + ":" + roleItem.getCode());
BigDecimal roleRatio = getStoredRoleRatio( BigDecimal roleRatio = useDefaultProjectLeadRoleRatio
dbItem, specialtyItem.getCode(), roleItem.getCode(), defaultRoleRatioMap); && OutputSplitBizConstants.SPECIALTY_PROJECT_LEAD.equals(specialtyItem.getCode())
? ratio(defaultRoleRatioMap.get(roleItem.getCode()))
: getStoredRoleRatio(dbItem, specialtyItem.getCode(), roleItem.getCode(), defaultRoleRatioMap);
BigDecimal roleAmount = multiplyAmount(specialtyAmount, roleRatio); BigDecimal roleAmount = multiplyAmount(specialtyAmount, roleRatio);
List<SpecialtyRolePersonRespVO> persons = buildRespPersons( List<SpecialtyRolePersonRespVO> persons = buildRespPersons(
dbItem, specialtyItem.getCode(), roleItem.getCode(), roleAmount, roleRatio, projectRolePersonMap); dbItem, specialtyItem.getCode(), roleItem.getCode(), roleAmount, projectRolePersonMap, personMap);
SpecialtyRoleSplitRespVO respVO = dbItem == null SpecialtyRoleSplitRespVO respVO = dbItem == null
? new SpecialtyRoleSplitRespVO() ? new SpecialtyRoleSplitRespVO()
: BeanUtils.toBean(dbItem, SpecialtyRoleSplitRespVO.class); : BeanUtils.toBean(dbItem, SpecialtyRoleSplitRespVO.class);
@@ -102,7 +204,7 @@ public class SpecialtyRoleSplitServiceImpl implements SpecialtyRoleSplitService
+ OutputSplitBizConstants.getRoleSortNo(roleItem.getCode())); + OutputSplitBizConstants.getRoleSortNo(roleItem.getCode()));
} }
respVO.setPlanningId(planning.getId()); respVO.setPlanningId(planning.getId());
respVO.setProjectName(project.getProjectName()); respVO.setProjectName(project == null ? "" : project.getProjectName());
respVO.setPlanningContent(planning.getPlanningContent()); respVO.setPlanningContent(planning.getPlanningContent());
respVO.setSpecialtyCode(specialtyItem.getCode()); respVO.setSpecialtyCode(specialtyItem.getCode());
respVO.setSpecialtyName(specialtyItem.getName()); respVO.setSpecialtyName(specialtyItem.getName());
@@ -118,7 +220,35 @@ public class SpecialtyRoleSplitServiceImpl implements SpecialtyRoleSplitService
return result; return result;
} }
private boolean shouldUseDefaultProjectLeadRoleRatio(Map<String, SpecialtyRoleSplitDO> dbMap,
Map<String, List<ProjectRolePersonDO>> projectRolePersonMap) {
if (projectRolePersonMap == null || projectRolePersonMap.isEmpty()) {
return false;
}
boolean hasProjectLeadPerson = (projectRolePersonMap.get(OutputSplitBizConstants.ROLE_PROJECT_MANAGER) != null
&& !projectRolePersonMap.get(OutputSplitBizConstants.ROLE_PROJECT_MANAGER).isEmpty())
|| (projectRolePersonMap.get(OutputSplitBizConstants.ROLE_ENGINEERING_PRINCIPAL) != null
&& !projectRolePersonMap.get(OutputSplitBizConstants.ROLE_ENGINEERING_PRINCIPAL).isEmpty());
if (!hasProjectLeadPerson || dbMap == null || dbMap.isEmpty()) {
return false;
}
BigDecimal storedTotal = ZERO_RATIO;
boolean hasStoredProjectLead = false;
for (String roleCode : Arrays.asList(
OutputSplitBizConstants.ROLE_PROJECT_MANAGER,
OutputSplitBizConstants.ROLE_ENGINEERING_PRINCIPAL)) {
SpecialtyRoleSplitDO dbItem = dbMap.get(OutputSplitBizConstants.SPECIALTY_PROJECT_LEAD + ":" + roleCode);
if (dbItem == null) {
continue;
}
hasStoredProjectLead = true;
storedTotal = storedTotal.add(ratio(dbItem.getRoleRatio())).setScale(RATIO_SCALE, RoundingMode.HALF_UP);
}
return hasStoredProjectLead && storedTotal.compareTo(ZERO_RATIO) == 0;
}
@Override @Override
@Transactional(rollbackFor = Exception.class)
public void saveSpecialtyRoleSplitBatch(SpecialtyRoleSplitBatchSaveReqVO reqVO) { public void saveSpecialtyRoleSplitBatch(SpecialtyRoleSplitBatchSaveReqVO reqVO) {
ProjectPlanningDO planning = validatePlanningExists(reqVO.getPlanningId()); ProjectPlanningDO planning = validatePlanningExists(reqVO.getPlanningId());
ProjectOutputSplitDO outputSplit = projectOutputSplitService.getOrCreateProjectOutputSplit(reqVO.getPlanningId()); ProjectOutputSplitDO outputSplit = projectOutputSplitService.getOrCreateProjectOutputSplit(reqVO.getPlanningId());
@@ -127,8 +257,23 @@ public class SpecialtyRoleSplitServiceImpl implements SpecialtyRoleSplitService
item -> item.getSpecialtyCode() + ":" + item.getRoleCode(), item -> item, (a, b) -> b)); item -> item.getSpecialtyCode() + ":" + item.getRoleCode(), item -> item, (a, b) -> b));
Map<String, Map<String, SpecialtyRoleSplitSaveItemReqVO>> groupedMap = buildGroupedInput(reqVO.getItems()); Map<String, Map<String, SpecialtyRoleSplitSaveItemReqVO>> groupedMap = buildGroupedInput(reqVO.getItems());
BigDecimal assessmentOutputValue = planning.getAssessmentOutputValue(); BigDecimal assessmentOutputValue = planning.getAssessmentOutputValue();
boolean temporarySave = Boolean.TRUE.equals(reqVO.getTemporarySave());
saveSpecialtyRoleSplits(outputSplit, dbMap, groupedMap, assessmentOutputValue, !temporarySave);
}
/**
* 专业人员分配共用保存流程:正式保存执行强校验,临时保存仅做基础格式处理后落库。
*/
private void saveSpecialtyRoleSplits(ProjectOutputSplitDO outputSplit,
Map<String, SpecialtyRoleSplitDO> dbMap,
Map<String, Map<String, SpecialtyRoleSplitSaveItemReqVO>> groupedMap,
BigDecimal assessmentOutputValue,
boolean strictValidate) {
for (OutputSplitBizConstants.SpecialtyItem specialtyItem : OutputSplitBizConstants.ASSIGNMENT_SPECIALTY_ITEMS) { for (OutputSplitBizConstants.SpecialtyItem specialtyItem : OutputSplitBizConstants.ASSIGNMENT_SPECIALTY_ITEMS) {
if (!groupedMap.containsKey(specialtyItem.getCode())) {
continue;
}
Map<String, SpecialtyRoleSplitSaveItemReqVO> roleMap = groupedMap.getOrDefault( Map<String, SpecialtyRoleSplitSaveItemReqVO> roleMap = groupedMap.getOrDefault(
specialtyItem.getCode(), new LinkedHashMap<>()); specialtyItem.getCode(), new LinkedHashMap<>());
BigDecimal roleTotal = ZERO_RATIO; BigDecimal roleTotal = ZERO_RATIO;
@@ -137,28 +282,35 @@ public class SpecialtyRoleSplitServiceImpl implements SpecialtyRoleSplitService
BigDecimal roleRatio = getSaveRoleRatio(roleMap, specialtyItem.getCode(), roleItem.getCode()); BigDecimal roleRatio = getSaveRoleRatio(roleMap, specialtyItem.getCode(), roleItem.getCode());
BigDecimal roleAmount = multiplyAmount(specialtyAmount, roleRatio); BigDecimal roleAmount = multiplyAmount(specialtyAmount, roleRatio);
List<SpecialtyRolePersonSaveReqVO> persons = normalizePersons( List<SpecialtyRolePersonSaveReqVO> persons = normalizePersons(
getSavePersons(roleMap, roleItem.getCode())); getSavePersons(roleMap, roleItem.getCode()), strictValidate);
validateRolePersons(roleItem.getCode(), roleAmount, persons); if (strictValidate) {
validateRolePersons(roleItem.getCode(), roleAmount, persons);
}
roleTotal = roleTotal.add(roleRatio).setScale(RATIO_SCALE, RoundingMode.HALF_UP); roleTotal = roleTotal.add(roleRatio).setScale(RATIO_SCALE, RoundingMode.HALF_UP);
upsertRole(dbMap, outputSplit.getId(), specialtyItem.getCode(), specialtyItem.getName(), SpecialtyRoleSplitDO role = upsertRole(dbMap, outputSplit.getId(), specialtyItem.getCode(),
roleItem.getCode(), roleRatio, specialtyItem.getName(), roleItem.getCode(), roleRatio);
OutputSplitBizConstants.SPECIALTY_PROJECT_LEAD.equals(specialtyItem.getCode()) refreshRolePersons(role, outputSplit, persons);
? null : toPersonJson(persons)); }
if (strictValidate) {
validateRoleTotal(roleTotal);
} }
validateRoleTotal(roleTotal);
} }
} }
@Override @Override
@Transactional(rollbackFor = Exception.class)
public void deleteByOutputSplitId(Long outputSplitId) { public void deleteByOutputSplitId(Long outputSplitId) {
specialtyRoleSplitPersonMapper.deleteByOutputSplitId(outputSplitId);
specialtyRoleSplitMapper.delete(SpecialtyRoleSplitDO::getOutputSplitId, outputSplitId); specialtyRoleSplitMapper.delete(SpecialtyRoleSplitDO::getOutputSplitId, outputSplitId);
} }
@Override @Override
@Transactional(rollbackFor = Exception.class)
public void deleteByOutputSplitIds(List<Long> outputSplitIds) { public void deleteByOutputSplitIds(List<Long> outputSplitIds) {
if (outputSplitIds == null || outputSplitIds.isEmpty()) { if (outputSplitIds == null || outputSplitIds.isEmpty()) {
return; return;
} }
specialtyRoleSplitPersonMapper.deleteByOutputSplitIds(outputSplitIds);
specialtyRoleSplitMapper.delete(new cn.iocoder.lyzsys.framework.mybatis.core.query.LambdaQueryWrapperX<SpecialtyRoleSplitDO>() specialtyRoleSplitMapper.delete(new cn.iocoder.lyzsys.framework.mybatis.core.query.LambdaQueryWrapperX<SpecialtyRoleSplitDO>()
.in(SpecialtyRoleSplitDO::getOutputSplitId, outputSplitIds)); .in(SpecialtyRoleSplitDO::getOutputSplitId, outputSplitIds));
} }
@@ -181,8 +333,9 @@ public class SpecialtyRoleSplitServiceImpl implements SpecialtyRoleSplitService
return result; return result;
} }
private void upsertRole(Map<String, SpecialtyRoleSplitDO> dbMap, Long outputSplitId, String specialtyCode, private SpecialtyRoleSplitDO upsertRole(Map<String, SpecialtyRoleSplitDO> dbMap, Long outputSplitId,
String specialtyName, String roleCode, BigDecimal roleRatio, String personsJson) { String specialtyCode, String specialtyName, String roleCode,
BigDecimal roleRatio) {
String key = specialtyCode + ":" + roleCode; String key = specialtyCode + ":" + roleCode;
SpecialtyRoleSplitDO dbItem = dbMap.get(key); SpecialtyRoleSplitDO dbItem = dbMap.get(key);
Integer sortNo = dbItem != null && dbItem.getSortNo() != null Integer sortNo = dbItem != null && dbItem.getSortNo() != null
@@ -197,10 +350,10 @@ public class SpecialtyRoleSplitServiceImpl implements SpecialtyRoleSplitService
createObj.setRoleCode(roleCode); createObj.setRoleCode(roleCode);
createObj.setRoleName(OutputSplitBizConstants.getRoleName(roleCode)); createObj.setRoleName(OutputSplitBizConstants.getRoleName(roleCode));
createObj.setRoleRatio(ratio(roleRatio)); createObj.setRoleRatio(ratio(roleRatio));
createObj.setPersonsJson(personsJson);
createObj.setSortNo(sortNo); createObj.setSortNo(sortNo);
specialtyRoleSplitMapper.insert(createObj); specialtyRoleSplitMapper.insert(createObj);
return; dbMap.put(key, createObj);
return createObj;
} }
SpecialtyRoleSplitDO updateObj = new SpecialtyRoleSplitDO(); SpecialtyRoleSplitDO updateObj = new SpecialtyRoleSplitDO();
updateObj.setId(dbItem.getId()); updateObj.setId(dbItem.getId());
@@ -210,9 +363,46 @@ public class SpecialtyRoleSplitServiceImpl implements SpecialtyRoleSplitService
updateObj.setRoleCode(roleCode); updateObj.setRoleCode(roleCode);
updateObj.setRoleName(OutputSplitBizConstants.getRoleName(roleCode)); updateObj.setRoleName(OutputSplitBizConstants.getRoleName(roleCode));
updateObj.setRoleRatio(ratio(roleRatio)); updateObj.setRoleRatio(ratio(roleRatio));
updateObj.setPersonsJson(personsJson);
updateObj.setSortNo(sortNo); updateObj.setSortNo(sortNo);
specialtyRoleSplitMapper.updateById(updateObj); specialtyRoleSplitMapper.updateById(updateObj);
dbMap.put(key, updateObj);
return updateObj;
}
private void refreshRolePersons(SpecialtyRoleSplitDO role, ProjectOutputSplitDO outputSplit,
List<SpecialtyRolePersonSaveReqVO> persons) {
if (role == null || role.getId() == null) {
return;
}
specialtyRoleSplitPersonMapper.deleteByRoleSplitId(role.getId());
if (OutputSplitBizConstants.SPECIALTY_PROJECT_LEAD.equals(role.getSpecialtyCode())
|| persons == null || persons.isEmpty()) {
return;
}
List<SpecialtyRoleSplitPersonDO> createList = new ArrayList<>();
for (int i = 0; i < persons.size(); i++) {
SpecialtyRolePersonSaveReqVO person = persons.get(i);
if (person == null || person.getEmployeeId() == null) {
continue;
}
SpecialtyRoleSplitPersonDO createObj = new SpecialtyRoleSplitPersonDO();
createObj.setRoleSplitId(role.getId());
createObj.setOutputSplitId(outputSplit.getId());
createObj.setProjectId(outputSplit.getProjectId());
createObj.setPlanningId(outputSplit.getPlanningId());
createObj.setSpecialtyCode(role.getSpecialtyCode());
createObj.setSpecialtyName(role.getSpecialtyName());
createObj.setRoleCode(role.getRoleCode());
createObj.setRoleName(role.getRoleName());
createObj.setEmployeeId(person.getEmployeeId());
createObj.setEmployeeName(person.getEmployeeName());
createObj.setPersonRatio(ratio(person.getPersonRatio()));
createObj.setSortNo(i + 1);
createList.add(createObj);
}
if (!createList.isEmpty()) {
specialtyRoleSplitPersonMapper.insertBatch(createList);
}
} }
private List<SpecialtyRolePersonSaveReqVO> getSavePersons(Map<String, SpecialtyRoleSplitSaveItemReqVO> roleMap, private List<SpecialtyRolePersonSaveReqVO> getSavePersons(Map<String, SpecialtyRoleSplitSaveItemReqVO> roleMap,
@@ -234,7 +424,8 @@ public class SpecialtyRoleSplitServiceImpl implements SpecialtyRoleSplitService
return roleRatio; return roleRatio;
} }
private List<SpecialtyRolePersonSaveReqVO> normalizePersons(List<SpecialtyRolePersonSaveReqVO> persons) { private List<SpecialtyRolePersonSaveReqVO> normalizePersons(List<SpecialtyRolePersonSaveReqVO> persons,
boolean strictValidate) {
List<SpecialtyRolePersonSaveReqVO> result = new ArrayList<>(); List<SpecialtyRolePersonSaveReqVO> result = new ArrayList<>();
if (persons == null || persons.isEmpty()) { if (persons == null || persons.isEmpty()) {
return result; return result;
@@ -250,14 +441,18 @@ public class SpecialtyRoleSplitServiceImpl implements SpecialtyRoleSplitService
if (!hasEmployee && !hasRatio) { if (!hasEmployee && !hasRatio) {
continue; continue;
} }
if (!hasEmployee || !hasRatio) { if (!strictValidate && !hasEmployee) {
// 临时保存允许半成品输入,没有选员工的行不落库。
continue;
}
if (strictValidate && (!hasEmployee || !hasRatio)) {
throw exception(SPECIALTY_ROLE_SPLIT_PERSON_INVALID); throw exception(SPECIALTY_ROLE_SPLIT_PERSON_INVALID);
} }
EmployeeDO employee = employeeService.validateEmployeeExists(employeeId); EmployeeDO employee = employeeService.validateEmployeeExists(employeeId);
SpecialtyRolePersonSaveReqVO normalized = new SpecialtyRolePersonSaveReqVO(); SpecialtyRolePersonSaveReqVO normalized = new SpecialtyRolePersonSaveReqVO();
normalized.setEmployeeId(employeeId); normalized.setEmployeeId(employeeId);
normalized.setEmployeeName(employee.getEmployeeName()); normalized.setEmployeeName(employee.getEmployeeName());
BigDecimal normalizedRatio = ratio(personRatio); BigDecimal normalizedRatio = ratio(strictValidate ? personRatio : (personRatio == null ? ZERO_RATIO : personRatio));
if (normalizedRatio.compareTo(ZERO_RATIO) < 0 || normalizedRatio.compareTo(ONE_RATIO) > 0) { if (normalizedRatio.compareTo(ZERO_RATIO) < 0 || normalizedRatio.compareTo(ONE_RATIO) > 0) {
throw exception(SPECIALTY_ROLE_SPLIT_PERSON_RATIO_INVALID); throw exception(SPECIALTY_ROLE_SPLIT_PERSON_RATIO_INVALID);
} }
@@ -298,13 +493,13 @@ public class SpecialtyRoleSplitServiceImpl implements SpecialtyRoleSplitService
private List<SpecialtyRolePersonRespVO> buildRespPersons(SpecialtyRoleSplitDO dbItem, String specialtyCode, private List<SpecialtyRolePersonRespVO> buildRespPersons(SpecialtyRoleSplitDO dbItem, String specialtyCode,
String roleCode, BigDecimal roleAmount, String roleCode, BigDecimal roleAmount,
BigDecimal roleRatio, Map<String, List<ProjectRolePersonDO>> projectRolePersonMap,
Map<String, List<ProjectRolePersonDO>> projectRolePersonMap) { Map<Long, List<SpecialtyRoleSplitPersonDO>> personMap) {
List<SpecialtyRolePersonSaveReqVO> sourcePersons; List<SpecialtyRolePersonSaveReqVO> sourcePersons;
if (OutputSplitBizConstants.SPECIALTY_PROJECT_LEAD.equals(specialtyCode)) { if (OutputSplitBizConstants.SPECIALTY_PROJECT_LEAD.equals(specialtyCode)) {
sourcePersons = buildDefaultProjectLeadPersons(projectRolePersonMap.get(roleCode)); sourcePersons = buildDefaultProjectLeadPersons(projectRolePersonMap.get(roleCode));
} else { } else {
sourcePersons = parseStoredPersons(dbItem); sourcePersons = buildStoredPersons(dbItem, personMap);
} }
List<SpecialtyRolePersonRespVO> result = new ArrayList<>(); List<SpecialtyRolePersonRespVO> result = new ArrayList<>();
for (SpecialtyRolePersonSaveReqVO person : sourcePersons) { for (SpecialtyRolePersonSaveReqVO person : sourcePersons) {
@@ -318,12 +513,13 @@ public class SpecialtyRoleSplitServiceImpl implements SpecialtyRoleSplitService
return result; return result;
} }
private List<SpecialtyRolePersonSaveReqVO> parseStoredPersons(SpecialtyRoleSplitDO dbItem) { private List<SpecialtyRolePersonSaveReqVO> buildStoredPersons(SpecialtyRoleSplitDO dbItem,
if (dbItem == null || dbItem.getPersonsJson() == null || dbItem.getPersonsJson().trim().isEmpty()) { Map<Long, List<SpecialtyRoleSplitPersonDO>> personMap) {
if (dbItem == null || dbItem.getId() == null || personMap == null || personMap.isEmpty()) {
return new ArrayList<>(); return new ArrayList<>();
} }
List<SpecialtyRolePersonSaveReqVO> persons = JsonUtils.parseArray(dbItem.getPersonsJson(), SpecialtyRolePersonSaveReqVO.class); List<SpecialtyRoleSplitPersonDO> persons = personMap.get(dbItem.getId());
if (persons == null) { if (persons == null || persons.isEmpty()) {
return new ArrayList<>(); return new ArrayList<>();
} }
return persons.stream() return persons.stream()
@@ -401,10 +597,6 @@ public class SpecialtyRoleSplitServiceImpl implements SpecialtyRoleSplitService
return projectOutputSplitService.getSpecialtyAmount(outputSplit, assessmentOutputValue, specialtyCode); return projectOutputSplitService.getSpecialtyAmount(outputSplit, assessmentOutputValue, specialtyCode);
} }
private String toPersonJson(List<SpecialtyRolePersonSaveReqVO> persons) {
return persons == null || persons.isEmpty() ? null : JsonUtils.toJsonString(persons);
}
private BigDecimal sumPersonRatios(List<SpecialtyRolePersonSaveReqVO> persons) { private BigDecimal sumPersonRatios(List<SpecialtyRolePersonSaveReqVO> persons) {
BigDecimal sum = ZERO_RATIO; BigDecimal sum = ZERO_RATIO;
if (persons == null || persons.isEmpty()) { if (persons == null || persons.isEmpty()) {

Some files were not shown because too many files have changed in this diff Show More