diff --git a/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/outputsplit/ProjectOutputSplitController.java b/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/outputsplit/ProjectOutputSplitController.java index 85d6251..9def010 100644 --- a/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/outputsplit/ProjectOutputSplitController.java +++ b/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/outputsplit/ProjectOutputSplitController.java @@ -1,9 +1,17 @@ package cn.iocoder.lyzsys.module.tjt.controller.admin.outputsplit; 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.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.planning.ProjectPlanningService; +import cn.iocoder.lyzsys.module.tjt.service.planningquarter.ProjectPlanningQuarterService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -13,6 +21,11 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.validation.Valid; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Collections; +import java.util.List; +import java.util.Map; import static cn.iocoder.lyzsys.framework.common.pojo.CommonResult.success; @@ -22,8 +35,15 @@ import static cn.iocoder.lyzsys.framework.common.pojo.CommonResult.success; @Validated public class ProjectOutputSplitController { + private static final int RATIO_SCALE = 4; + private static final BigDecimal ZERO_RATIO = BigDecimal.ZERO.setScale(RATIO_SCALE, RoundingMode.HALF_UP); + @Resource private ProjectOutputSplitService projectOutputSplitService; + @Resource + private ProjectPlanningService projectPlanningService; + @Resource + private ProjectPlanningQuarterService projectPlanningQuarterService; @GetMapping("/get-by-planning") @Operation(summary = "根据合约规划获得页面4拆分比例") @@ -33,6 +53,29 @@ public class ProjectOutputSplitController { 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 getProjectOutputSplitPlanningDetail( + @RequestParam("planningId") Long planningId) { + ProjectPlanningDO planning = projectPlanningService.getProjectPlanning(planningId); + if (planning == null) { + return success(null); + } + ProjectOutputSplitPlanningDetailRespVO respVO = new ProjectOutputSplitPlanningDetailRespVO(); + Map allocatedAmountMap = + projectPlanningService.getAllocatedAmountMap(Collections.singleton(planningId)); + respVO.setPlanning(BeanUtils.toBean(planning, ProjectPlanningRespVO.class, + planningRespVO -> fillDistributionSummary(planningRespVO, allocatedAmountMap))); + respVO.setOutputSplit(projectOutputSplitService.getProjectOutputSplit(planningId)); + + List quarterList = + projectPlanningQuarterService.getProjectPlanningQuarterListByPlanningId(planningId); + respVO.setQuarters(BeanUtils.toBean(quarterList, ProjectPlanningQuarterRespVO.class)); + return success(respVO); + } + @PutMapping("/save") @Operation(summary = "保存页面4拆分比例") @PreAuthorize("@ss.hasPermission('tjt:output-split:update')") @@ -40,4 +83,15 @@ public class ProjectOutputSplitController { return success(projectOutputSplitService.saveProjectOutputSplit(reqVO)); } + private void fillDistributionSummary(ProjectPlanningRespVO respVO, Map 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)); + } + } diff --git a/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/outputsplit/vo/ProjectOutputSplitPlanningDetailRespVO.java b/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/outputsplit/vo/ProjectOutputSplitPlanningDetailRespVO.java new file mode 100644 index 0000000..b52dbc4 --- /dev/null +++ b/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/outputsplit/vo/ProjectOutputSplitPlanningDetailRespVO.java @@ -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 quarters = Collections.emptyList(); + +} diff --git a/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/planning/ProjectPlanningController.java b/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/planning/ProjectPlanningController.java index f6be548..f66db31 100644 --- a/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/planning/ProjectPlanningController.java +++ b/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/planning/ProjectPlanningController.java @@ -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.util.collection.CollectionUtils; 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.ProjectPlanningRespVO; 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.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.planningguidedetail.ProjectPlanningGuideDetailService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -37,6 +42,8 @@ public class ProjectPlanningController { @Resource private ProjectPlanningService projectPlanningService; + @Resource + private ProjectPlanningGuideDetailService projectPlanningGuideDetailService; @PostMapping("/create") @Operation(summary = "创建合约规划") @@ -97,6 +104,30 @@ public class ProjectPlanningController { 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 getProjectPlanningOutputEditDetail(@RequestParam("id") Long id) { + ProjectPlanningDO planning = projectPlanningService.getProjectPlanning(id); + if (planning == null) { + return success(null); + } + + Map 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 guideDetails = + projectPlanningGuideDetailService.getProjectPlanningGuideDetailListByPlanningId(id); + respVO.setGuideDetails(BeanUtils.toBean(guideDetails, ProjectPlanningGuideDetailRespVO.class)); + } + return success(respVO); + } + @GetMapping("/list-by-project") @Operation(summary = "根据项目获得合约规划列表") @Parameter(name = "projectId", description = "项目 ID", required = true, example = "1") diff --git a/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/planning/vo/ProjectPlanningOutputEditDetailRespVO.java b/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/planning/vo/ProjectPlanningOutputEditDetailRespVO.java new file mode 100644 index 0000000..39bcb86 --- /dev/null +++ b/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/planning/vo/ProjectPlanningOutputEditDetailRespVO.java @@ -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 guideDetails = Collections.emptyList(); + +} diff --git a/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/planningquarter/ProjectPlanningQuarterController.java b/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/planningquarter/ProjectPlanningQuarterController.java index 94f2410..5d6fe87 100644 --- a/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/planningquarter/ProjectPlanningQuarterController.java +++ b/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/planningquarter/ProjectPlanningQuarterController.java @@ -2,9 +2,13 @@ package cn.iocoder.lyzsys.module.tjt.controller.admin.planningquarter; import cn.iocoder.lyzsys.framework.common.pojo.CommonResult; import cn.iocoder.lyzsys.framework.common.util.object.BeanUtils; +import cn.iocoder.lyzsys.module.tjt.controller.admin.planning.vo.ProjectPlanningRespVO; +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.ProjectPlanningQuarterSaveReqVO; +import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planning.ProjectPlanningDO; import cn.iocoder.lyzsys.module.tjt.dal.dataobject.planningquarter.ProjectPlanningQuarterDO; +import cn.iocoder.lyzsys.module.tjt.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.Parameter; @@ -15,7 +19,11 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.validation.Valid; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Collections; import java.util.List; +import java.util.Map; import static cn.iocoder.lyzsys.framework.common.pojo.CommonResult.success; @@ -25,8 +33,13 @@ import static cn.iocoder.lyzsys.framework.common.pojo.CommonResult.success; @Validated 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 private ProjectPlanningQuarterService projectPlanningQuarterService; + @Resource + private ProjectPlanningService projectPlanningService; @PostMapping("/create") @Operation(summary = "创建季度分配") @@ -80,4 +93,37 @@ public class ProjectPlanningQuarterController { 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 getProjectPlanningQuarterPlanningDetail( + @RequestParam("planningId") Long planningId) { + ProjectPlanningDO planning = projectPlanningService.getProjectPlanning(planningId); + if (planning == null) { + return success(null); + } + List quarterList = + projectPlanningQuarterService.getProjectPlanningQuarterListByPlanningId(planningId); + + ProjectPlanningQuarterPlanningDetailRespVO respVO = new ProjectPlanningQuarterPlanningDetailRespVO(); + Map allocatedAmountMap = + projectPlanningService.getAllocatedAmountMap(Collections.singleton(planningId)); + respVO.setPlanning(BeanUtils.toBean(planning, ProjectPlanningRespVO.class, + planningRespVO -> fillDistributionSummary(planningRespVO, allocatedAmountMap))); + respVO.setQuarters(BeanUtils.toBean(quarterList, ProjectPlanningQuarterRespVO.class)); + return success(respVO); + } + + private void fillDistributionSummary(ProjectPlanningRespVO respVO, Map 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)); + } + } diff --git a/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/planningquarter/vo/ProjectPlanningQuarterPlanningDetailRespVO.java b/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/planningquarter/vo/ProjectPlanningQuarterPlanningDetailRespVO.java new file mode 100644 index 0000000..6d46853 --- /dev/null +++ b/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/planningquarter/vo/ProjectPlanningQuarterPlanningDetailRespVO.java @@ -0,0 +1,20 @@ +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 quarters = Collections.emptyList(); + +} diff --git a/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/specialtyrolesplit/vo/SpecialtyRoleSplitBatchSaveReqVO.java b/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/specialtyrolesplit/vo/SpecialtyRoleSplitBatchSaveReqVO.java index bb3f8c5..f96859a 100644 --- a/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/specialtyrolesplit/vo/SpecialtyRoleSplitBatchSaveReqVO.java +++ b/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/controller/admin/specialtyrolesplit/vo/SpecialtyRoleSplitBatchSaveReqVO.java @@ -21,4 +21,7 @@ public class SpecialtyRoleSplitBatchSaveReqVO { @Valid private List items; + @Schema(description = "是否临时保存。true 时仅做基础格式处理,跳过角色合计、设计人员必填等强校验", example = "false") + private Boolean temporarySave; + } diff --git a/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/service/outputsplit/ProjectOutputSplitServiceImpl.java b/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/service/outputsplit/ProjectOutputSplitServiceImpl.java index 99bdf87..24e6a5c 100644 --- a/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/service/outputsplit/ProjectOutputSplitServiceImpl.java +++ b/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/service/outputsplit/ProjectOutputSplitServiceImpl.java @@ -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.projectroleperson.ProjectRolePersonMapper; import cn.iocoder.lyzsys.module.tjt.enums.OutputSplitBizConstants; +import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -76,7 +77,22 @@ public class ProjectOutputSplitServiceImpl implements ProjectOutputSplitService outputSplit.setProjectId(planning.getProjectId()); outputSplit.setYear(getPlanningYear(planning)); 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 { ProjectOutputSplitDO updateObj = BeanUtils.toBean(reqVO, ProjectOutputSplitDO.class); updateObj.setId(outputSplit.getId()); @@ -97,8 +113,17 @@ public class ProjectOutputSplitServiceImpl implements ProjectOutputSplitService return outputSplit; } ProjectOutputSplitDO createObj = buildDefaultOutputSplit(planning); - projectOutputSplitMapper.insert(createObj); - return createObj; + try { + projectOutputSplitMapper.insert(createObj); + return createObj; + } catch (DuplicateKeyException ex) { + // 唯一索引兜底并发创建,同一合约规划已存在时直接复用已有记录。 + ProjectOutputSplitDO existing = projectOutputSplitMapper.selectByPlanningId(planningId); + if (existing != null) { + return existing; + } + throw ex; + } } @Override diff --git a/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/service/specialtyrolesplit/SpecialtyRoleSplitServiceImpl.java b/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/service/specialtyrolesplit/SpecialtyRoleSplitServiceImpl.java index 6a3e588..5d8203c 100644 --- a/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/service/specialtyrolesplit/SpecialtyRoleSplitServiceImpl.java +++ b/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/service/specialtyrolesplit/SpecialtyRoleSplitServiceImpl.java @@ -203,7 +203,19 @@ public class SpecialtyRoleSplitServiceImpl implements SpecialtyRoleSplitService item -> item.getSpecialtyCode() + ":" + item.getRoleCode(), item -> item, (a, b) -> b)); Map> groupedMap = buildGroupedInput(reqVO.getItems()); BigDecimal assessmentOutputValue = planning.getAssessmentOutputValue(); + boolean temporarySave = Boolean.TRUE.equals(reqVO.getTemporarySave()); + saveSpecialtyRoleSplits(outputSplit, dbMap, groupedMap, assessmentOutputValue, !temporarySave); + } + + /** + * 专业人员分配共用保存流程:正式保存执行强校验,临时保存仅做基础格式处理后落库。 + */ + private void saveSpecialtyRoleSplits(ProjectOutputSplitDO outputSplit, + Map dbMap, + Map> groupedMap, + BigDecimal assessmentOutputValue, + boolean strictValidate) { for (OutputSplitBizConstants.SpecialtyItem specialtyItem : OutputSplitBizConstants.ASSIGNMENT_SPECIALTY_ITEMS) { Map roleMap = groupedMap.getOrDefault( specialtyItem.getCode(), new LinkedHashMap<>()); @@ -213,14 +225,18 @@ public class SpecialtyRoleSplitServiceImpl implements SpecialtyRoleSplitService BigDecimal roleRatio = getSaveRoleRatio(roleMap, specialtyItem.getCode(), roleItem.getCode()); BigDecimal roleAmount = multiplyAmount(specialtyAmount, roleRatio); List persons = normalizePersons( - getSavePersons(roleMap, roleItem.getCode())); - validateRolePersons(roleItem.getCode(), roleAmount, persons); + getSavePersons(roleMap, roleItem.getCode()), strictValidate); + if (strictValidate) { + validateRolePersons(roleItem.getCode(), roleAmount, persons); + } roleTotal = roleTotal.add(roleRatio).setScale(RATIO_SCALE, RoundingMode.HALF_UP); SpecialtyRoleSplitDO role = upsertRole(dbMap, outputSplit.getId(), specialtyItem.getCode(), specialtyItem.getName(), roleItem.getCode(), roleRatio); refreshRolePersons(role, outputSplit, persons); } - validateRoleTotal(roleTotal); + if (strictValidate) { + validateRoleTotal(roleTotal); + } } } @@ -351,7 +367,8 @@ public class SpecialtyRoleSplitServiceImpl implements SpecialtyRoleSplitService return roleRatio; } - private List normalizePersons(List persons) { + private List normalizePersons(List persons, + boolean strictValidate) { List result = new ArrayList<>(); if (persons == null || persons.isEmpty()) { return result; @@ -367,14 +384,18 @@ public class SpecialtyRoleSplitServiceImpl implements SpecialtyRoleSplitService if (!hasEmployee && !hasRatio) { continue; } - if (!hasEmployee || !hasRatio) { + if (!strictValidate && !hasEmployee) { + // 临时保存允许半成品输入,没有选员工的行不落库。 + continue; + } + if (strictValidate && (!hasEmployee || !hasRatio)) { throw exception(SPECIALTY_ROLE_SPLIT_PERSON_INVALID); } EmployeeDO employee = employeeService.validateEmployeeExists(employeeId); SpecialtyRolePersonSaveReqVO normalized = new SpecialtyRolePersonSaveReqVO(); normalized.setEmployeeId(employeeId); 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) { throw exception(SPECIALTY_ROLE_SPLIT_PERSON_RATIO_INVALID); }