From e166428f5ebff8e8f7b1e3b10e108f4faf2a257b Mon Sep 17 00:00:00 2001 From: shl <1378304611@qq.com> Date: Thu, 8 Aug 2024 16:41:39 +0800 Subject: [PATCH] =?UTF-8?q?[feat]=20=E6=96=B0=E5=A2=9E=E9=A2=84=E7=AE=97?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/cms/api/contract/ContractApi.java | 24 ++ .../contract/dto/ContractDetailRespDTO.java | 38 +++ .../cms/api/contract/dto/ContractRespDTO.java | 44 +++ .../cms/api/outscontract/OutscontractApi.java | 14 + .../outscontract/dto/OutscontractRespDTO.java | 25 ++ .../module/cms/api/contract/ContractImpl.java | 44 +++ .../api/outscontract/OutscontractImpl.java | 38 +++ .../dal/mysql/contract/ContractMapper.java | 1 - .../service/contract/ContractServiceImpl.java | 10 +- .../pms/api/project/dto/ProjectRespDTO.java | 18 + .../module/pms/enums/ErrorCodeConstants.java | 9 + .../admin/budget/BudgetController.java | 17 +- .../admin/budget/vo/BudgetRespVO.java | 49 +++ .../admin/budget/vo/BudgetSaveReqVO.java | 51 +++ .../pms/service/budget/BudgetService.java | 12 +- .../pms/service/budget/BudgetServiceImpl.java | 313 +++++++++++++++++- 16 files changed, 677 insertions(+), 30 deletions(-) create mode 100644 yudao-module-cms/yudao-module-cms-api/src/main/java/cn/iocoder/yudao/module/cms/api/contract/ContractApi.java create mode 100644 yudao-module-cms/yudao-module-cms-api/src/main/java/cn/iocoder/yudao/module/cms/api/contract/dto/ContractDetailRespDTO.java create mode 100644 yudao-module-cms/yudao-module-cms-api/src/main/java/cn/iocoder/yudao/module/cms/api/contract/dto/ContractRespDTO.java create mode 100644 yudao-module-cms/yudao-module-cms-api/src/main/java/cn/iocoder/yudao/module/cms/api/outscontract/OutscontractApi.java create mode 100644 yudao-module-cms/yudao-module-cms-api/src/main/java/cn/iocoder/yudao/module/cms/api/outscontract/dto/OutscontractRespDTO.java create mode 100644 yudao-module-cms/yudao-module-cms-biz/src/main/java/cn/iocoder/yudao/module/cms/api/contract/ContractImpl.java create mode 100644 yudao-module-cms/yudao-module-cms-biz/src/main/java/cn/iocoder/yudao/module/cms/api/outscontract/OutscontractImpl.java diff --git a/yudao-module-cms/yudao-module-cms-api/src/main/java/cn/iocoder/yudao/module/cms/api/contract/ContractApi.java b/yudao-module-cms/yudao-module-cms-api/src/main/java/cn/iocoder/yudao/module/cms/api/contract/ContractApi.java new file mode 100644 index 000000000..35d773c71 --- /dev/null +++ b/yudao-module-cms/yudao-module-cms-api/src/main/java/cn/iocoder/yudao/module/cms/api/contract/ContractApi.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.cms.api.contract; + +import cn.iocoder.yudao.module.cms.api.contract.dto.ContractDetailRespDTO; +import cn.iocoder.yudao.module.cms.api.contract.dto.ContractRespDTO; + +public interface ContractApi { + + /** + * 获得合同部分信息 + */ + ContractRespDTO getContract(Long id); + + /** + * 获得合同detail信息 + */ + ContractDetailRespDTO getContractDetailById(Long id); + + + /** + * 判断合同是否存在 + */ + void vaildContractExist(Long id); + +} diff --git a/yudao-module-cms/yudao-module-cms-api/src/main/java/cn/iocoder/yudao/module/cms/api/contract/dto/ContractDetailRespDTO.java b/yudao-module-cms/yudao-module-cms-api/src/main/java/cn/iocoder/yudao/module/cms/api/contract/dto/ContractDetailRespDTO.java new file mode 100644 index 000000000..b6ada0022 --- /dev/null +++ b/yudao-module-cms/yudao-module-cms-api/src/main/java/cn/iocoder/yudao/module/cms/api/contract/dto/ContractDetailRespDTO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.cms.api.contract.dto; + +import lombok.Data; + +import java.math.BigDecimal; + +@Data +public class ContractDetailRespDTO { + /** + * 项目id + */ + private Long projectId; + /** + * 合同名称 + */ + private String name; + /** + * 合同类型 + */ + private String type; + /** + * 合同进展 + */ + private String progress; + /** + * 合同状态 + */ + private String status; + /** + * 签订合同总额 + */ + private BigDecimal amount; + /** + * 审定金额 + */ + private BigDecimal approvedAmount; + +} diff --git a/yudao-module-cms/yudao-module-cms-api/src/main/java/cn/iocoder/yudao/module/cms/api/contract/dto/ContractRespDTO.java b/yudao-module-cms/yudao-module-cms-api/src/main/java/cn/iocoder/yudao/module/cms/api/contract/dto/ContractRespDTO.java new file mode 100644 index 000000000..334fb3122 --- /dev/null +++ b/yudao-module-cms/yudao-module-cms-api/src/main/java/cn/iocoder/yudao/module/cms/api/contract/dto/ContractRespDTO.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.cms.api.contract.dto; + +import lombok.Data; + +import java.math.BigDecimal; + +@Data +public class ContractRespDTO { + + /** + * 项目id + */ + private Long projectId; + /** + * 合同名称 + */ + private String name; + /** + * 合同类型 + */ + private String type; + /** + * 合同进展 + */ + private String progress; + /** + * 合同状态 + */ + private String status; + /** + * 签订合同总额 + */ + private BigDecimal amount; + /** + * 审定金额 + */ + private BigDecimal approvedAmount; + /** + * 计费方式 + */ + private String countType; + + +} diff --git a/yudao-module-cms/yudao-module-cms-api/src/main/java/cn/iocoder/yudao/module/cms/api/outscontract/OutscontractApi.java b/yudao-module-cms/yudao-module-cms-api/src/main/java/cn/iocoder/yudao/module/cms/api/outscontract/OutscontractApi.java new file mode 100644 index 000000000..0d08070ad --- /dev/null +++ b/yudao-module-cms/yudao-module-cms-api/src/main/java/cn/iocoder/yudao/module/cms/api/outscontract/OutscontractApi.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.cms.api.outscontract; + +import cn.iocoder.yudao.module.cms.api.contract.dto.ContractRespDTO; +import cn.iocoder.yudao.module.cms.api.outscontract.dto.OutscontractRespDTO; + +import java.math.BigDecimal; +import java.util.List; + +public interface OutscontractApi { + + OutscontractRespDTO getOutsContract(Long id); + + BigDecimal getOutsContractAmount(Long contractId); +} diff --git a/yudao-module-cms/yudao-module-cms-api/src/main/java/cn/iocoder/yudao/module/cms/api/outscontract/dto/OutscontractRespDTO.java b/yudao-module-cms/yudao-module-cms-api/src/main/java/cn/iocoder/yudao/module/cms/api/outscontract/dto/OutscontractRespDTO.java new file mode 100644 index 000000000..2aa7f4235 --- /dev/null +++ b/yudao-module-cms/yudao-module-cms-api/src/main/java/cn/iocoder/yudao/module/cms/api/outscontract/dto/OutscontractRespDTO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.cms.api.outscontract.dto; + +import lombok.Data; + +import java.math.BigDecimal; + +@Data +public class OutscontractRespDTO { + /** + * 合同名称 + */ + private String name; + /** + * 主合同id + */ + private Long contractId; + /** + * 外包合同金额 + */ + private BigDecimal amount; + /** + * 编号 + */ + private String code; +} diff --git a/yudao-module-cms/yudao-module-cms-biz/src/main/java/cn/iocoder/yudao/module/cms/api/contract/ContractImpl.java b/yudao-module-cms/yudao-module-cms-biz/src/main/java/cn/iocoder/yudao/module/cms/api/contract/ContractImpl.java new file mode 100644 index 000000000..29bdefce3 --- /dev/null +++ b/yudao-module-cms/yudao-module-cms-biz/src/main/java/cn/iocoder/yudao/module/cms/api/contract/ContractImpl.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.cms.api.contract; + +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.cms.api.contract.dto.ContractDetailRespDTO; +import cn.iocoder.yudao.module.cms.api.contract.dto.ContractRespDTO; +import cn.iocoder.yudao.module.cms.dal.dataobject.contract.ContractDO; +import cn.iocoder.yudao.module.cms.dal.mysql.contract.ContractMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.cms.enums.ErrorCodeConstants.CONTRACT_NOT_EXISTS; +import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstants.PROJECT_NOT_EXISTS; + +@Service +@Validated +public class ContractImpl implements ContractApi{ + + @Resource + private ContractMapper contractMapper; + + @Override + public ContractRespDTO getContract(Long id) { + ContractDO contractDO = contractMapper.selectById(id); + ContractRespDTO contractRespDTO = BeanUtils.toBean(contractDO, ContractRespDTO.class); + return contractRespDTO; + } + + @Override + public ContractDetailRespDTO getContractDetailById(Long id) { + // 优化 + ContractDO contractRespDTO1 = contractMapper.selectById(id); + ContractDetailRespDTO contractDetailRespDTO = BeanUtils.toBean(contractRespDTO1, ContractDetailRespDTO.class); + return contractDetailRespDTO; + } + + @Override + public void vaildContractExist(Long id) { + if (contractMapper.selectById(id)==null) { + throw exception(CONTRACT_NOT_EXISTS); + } + } +} diff --git a/yudao-module-cms/yudao-module-cms-biz/src/main/java/cn/iocoder/yudao/module/cms/api/outscontract/OutscontractImpl.java b/yudao-module-cms/yudao-module-cms-biz/src/main/java/cn/iocoder/yudao/module/cms/api/outscontract/OutscontractImpl.java new file mode 100644 index 000000000..40468f3a4 --- /dev/null +++ b/yudao-module-cms/yudao-module-cms-biz/src/main/java/cn/iocoder/yudao/module/cms/api/outscontract/OutscontractImpl.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.cms.api.outscontract; + +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.cms.api.outscontract.dto.OutscontractRespDTO; +import cn.iocoder.yudao.module.cms.dal.dataobject.outscontract.OutsContractDO; +import cn.iocoder.yudao.module.cms.dal.mysql.outscontract.OutsContractMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; +import java.util.List; + +@Service +@Validated +public class OutscontractImpl implements OutscontractApi{ + + @Resource + private OutsContractMapper outsContractMapper; + + @Override + public OutscontractRespDTO getOutsContract(Long id) { + OutsContractDO outsContractDO = outsContractMapper.selectById(id); + OutscontractRespDTO outscontractRespDTO = BeanUtils.toBean(outsContractDO, OutscontractRespDTO.class); + return outscontractRespDTO; + } + + @Override + public BigDecimal getOutsContractAmount(Long contractId) { + List contractIds = outsContractMapper.selectList("contract_id", contractId); + BigDecimal res = new BigDecimal(0); + for (OutsContractDO contract:contractIds){ + res = res.add(contract.getAmount()); + } + return res; + } + +} diff --git a/yudao-module-cms/yudao-module-cms-biz/src/main/java/cn/iocoder/yudao/module/cms/dal/mysql/contract/ContractMapper.java b/yudao-module-cms/yudao-module-cms-biz/src/main/java/cn/iocoder/yudao/module/cms/dal/mysql/contract/ContractMapper.java index 1b5e5dd9b..3f1a77040 100644 --- a/yudao-module-cms/yudao-module-cms-biz/src/main/java/cn/iocoder/yudao/module/cms/dal/mysql/contract/ContractMapper.java +++ b/yudao-module-cms/yudao-module-cms-biz/src/main/java/cn/iocoder/yudao/module/cms/dal/mysql/contract/ContractMapper.java @@ -24,7 +24,6 @@ public interface ContractMapper extends BaseMapperX { .eqIfPresent(ContractDO::getStatus, reqVO.getStatus()) .eqIfPresent(ContractDO::getCountType, reqVO.getCountType()) ); - } } diff --git a/yudao-module-cms/yudao-module-cms-biz/src/main/java/cn/iocoder/yudao/module/cms/service/contract/ContractServiceImpl.java b/yudao-module-cms/yudao-module-cms-biz/src/main/java/cn/iocoder/yudao/module/cms/service/contract/ContractServiceImpl.java index dbb983b1f..fe9d38ee8 100644 --- a/yudao-module-cms/yudao-module-cms-biz/src/main/java/cn/iocoder/yudao/module/cms/service/contract/ContractServiceImpl.java +++ b/yudao-module-cms/yudao-module-cms-biz/src/main/java/cn/iocoder/yudao/module/cms/service/contract/ContractServiceImpl.java @@ -217,12 +217,12 @@ public class ContractServiceImpl implements ContractService { // 7.暂定结算数 √ ProjectRespDTO project = projectApi.getProject(projectId); - contractRespVO.setCode(project.getCode()); - contractRespVO.setDrawingCompany(project.getDrawingCompany()); - contractRespVO.setExpectedContractAmount(project.getContractAmount()); + contractRespVO.setCode(project.getCode()); // 项目编号 + contractRespVO.setDrawingCompany(project.getDrawingCompany()); // 出图公司 + contractRespVO.setExpectedContractAmount(project.getContractAmount()); // 预计合同金额 ProjectDetailRespDTO projectDetail = projectApi.getProjectDetailById(projectId); - contractRespVO.setTrackingDep(projectDetail.getTrackingDepName()); - contractRespVO.setProjectManager(projectDetail.getProjectManagerName()); + contractRespVO.setTrackingDep(projectDetail.getTrackingDepName()); // 主控部门 + contractRespVO.setProjectManager(projectDetail.getProjectManagerName()); // 项目经理 //分包合同商议提示 TODO 待优化 // ExtContractDO extContractDO = extContractMapper.selectOne("project_id", projectId); diff --git a/yudao-module-pms/yudao-module-pms-api/src/main/java/cn/iocoder/yudao/module/pms/api/project/dto/ProjectRespDTO.java b/yudao-module-pms/yudao-module-pms-api/src/main/java/cn/iocoder/yudao/module/pms/api/project/dto/ProjectRespDTO.java index df6b6f91c..599034a80 100644 --- a/yudao-module-pms/yudao-module-pms-api/src/main/java/cn/iocoder/yudao/module/pms/api/project/dto/ProjectRespDTO.java +++ b/yudao-module-pms/yudao-module-pms-api/src/main/java/cn/iocoder/yudao/module/pms/api/project/dto/ProjectRespDTO.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.pms.api.project.dto; +import cn.iocoder.yudao.module.pms.enums.DictTypeConstants; import lombok.Data; import java.math.BigDecimal; @@ -41,6 +42,23 @@ public class ProjectRespDTO { */ private BigDecimal contractAmount; + /** + * 跟踪编号 + */ + private String trackingCode; + + /** + * 名称 + */ + private String name; + + /** + * 类型 + * + * 枚举 {@link DictTypeConstants} + */ + private String type; + } diff --git a/yudao-module-pms/yudao-module-pms-api/src/main/java/cn/iocoder/yudao/module/pms/enums/ErrorCodeConstants.java b/yudao-module-pms/yudao-module-pms-api/src/main/java/cn/iocoder/yudao/module/pms/enums/ErrorCodeConstants.java index 058bb54fe..eccb301ae 100644 --- a/yudao-module-pms/yudao-module-pms-api/src/main/java/cn/iocoder/yudao/module/pms/enums/ErrorCodeConstants.java +++ b/yudao-module-pms/yudao-module-pms-api/src/main/java/cn/iocoder/yudao/module/pms/enums/ErrorCodeConstants.java @@ -24,4 +24,13 @@ public interface ErrorCodeConstants { ErrorCode RECEIVABLES_NOT_EXISTS = new ErrorCode(1_024_000_000, "应收款管理不存在"); // ========== 应收款管理历史记录 1_024_000_000 ========== ErrorCode RECEIVABLES_HISTORY_NOT_EXISTS = new ErrorCode(1_024_000_000, "应收款管理历史记录不存在"); + + // ========== 请求参数不存在 1_025_000_000 ========== + ErrorCode PARAM_NOT_EXISTS = new ErrorCode(1_024_100_000, "请求参数不存在"); + + ErrorCode PARAM_ERROR = new ErrorCode(1_024_200_000, "请求参数错误"); + + ErrorCode BUDGET_ALREADY_EXISTS = new ErrorCode(1_024_003_000, "该预算已经创建"); + + ErrorCode PROFIT_MARGIN_ERROR = new ErrorCode(1_024_004_000, "利润率计算错误"); } diff --git a/yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/budget/BudgetController.java b/yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/budget/BudgetController.java index 21589f45e..426b2a36e 100644 --- a/yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/budget/BudgetController.java +++ b/yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/budget/BudgetController.java @@ -8,7 +8,6 @@ import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Operation; -import jakarta.validation.constraints.*; import jakarta.validation.*; import jakarta.servlet.http.*; import java.util.*; @@ -24,9 +23,9 @@ import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; import cn.iocoder.yudao.module.pms.controller.admin.budget.vo.*; -import cn.iocoder.yudao.module.pms.dal.dataobject.budget.BudgetDO; import cn.iocoder.yudao.module.pms.service.budget.BudgetService; @Tag(name = "管理后台 - 预算管理") @@ -42,14 +41,14 @@ public class BudgetController { @Operation(summary = "创建预算管理") @PreAuthorize("@ss.hasPermission('pms:budget:create')") public CommonResult createBudget(@Valid @RequestBody BudgetSaveReqVO createReqVO) { - return success(budgetService.createBudget(createReqVO)); + return success(budgetService.createBudget(getLoginUserId(),createReqVO)); } @PutMapping("/update") @Operation(summary = "更新预算管理") @PreAuthorize("@ss.hasPermission('pms:budget:update')") public CommonResult updateBudget(@Valid @RequestBody BudgetSaveReqVO updateReqVO) { - budgetService.updateBudget(updateReqVO); + budgetService.updateBudget(getLoginUserId(),updateReqVO); return success(true); } @@ -67,16 +66,16 @@ public class BudgetController { @Parameter(name = "id", description = "编号", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('pms:budget:query')") public CommonResult getBudget(@RequestParam("id") Long id) { - BudgetDO budget = budgetService.getBudget(id); - return success(BeanUtils.toBean(budget, BudgetRespVO.class)); + BudgetRespVO budgetRespVO = budgetService.getBudget(id); + return success(budgetRespVO); } @GetMapping("/page") @Operation(summary = "获得预算管理分页") @PreAuthorize("@ss.hasPermission('pms:budget:query')") public CommonResult> getBudgetPage(@Valid BudgetPageReqVO pageReqVO) { - PageResult pageResult = budgetService.getBudgetPage(pageReqVO); - return success(BeanUtils.toBean(pageResult, BudgetRespVO.class)); + PageResult pageResult = budgetService.getBudgetPage(pageReqVO); + return success(pageResult); } @GetMapping("/export-excel") @@ -86,7 +85,7 @@ public class BudgetController { public void exportBudgetExcel(@Valid BudgetPageReqVO pageReqVO, HttpServletResponse response) throws IOException { pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); - List list = budgetService.getBudgetPage(pageReqVO).getList(); + List list = budgetService.getBudgetPage(pageReqVO).getList(); // 导出 Excel ExcelUtils.write(response, "预算管理.xls", "数据", BudgetRespVO.class, BeanUtils.toBean(list, BudgetRespVO.class)); diff --git a/yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/budget/vo/BudgetRespVO.java b/yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/budget/vo/BudgetRespVO.java index f7a775463..78f948c51 100644 --- a/yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/budget/vo/BudgetRespVO.java +++ b/yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/budget/vo/BudgetRespVO.java @@ -13,6 +13,55 @@ import com.alibaba.excel.annotation.*; @ExcelIgnoreUnannotated public class BudgetRespVO { + @Schema(description = "跟踪项目编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "XS24001") + @ExcelProperty("跟踪项目编号") + private String trackingProjectCode; + + @Schema(description = "项目编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "SJ24001") + @ExcelProperty("项目编号") + private String projectCode; + + @Schema(description = "跟踪项目名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "规划一路道路工程") + @ExcelProperty("跟踪项目名称") + private String trackingProjectName; + + @Schema(description = "项目类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "设计") + @ExcelProperty("项目类型") + private String projectType; + + @Schema(description = "预计合同金额", requiredMode = Schema.RequiredMode.REQUIRED,example = "200.0000") + @ExcelProperty("预计合同金额") + private BigDecimal expectedContractAmount; + + @Schema(description = "暂定结算数") + @ExcelProperty("暂定结算数") + private BigDecimal provisionalSettlement; + + @Schema(description = "包干/审定金额", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("包干/审定金额") + private BigDecimal approvedAmount; + + @Schema(description = "外包合同金额") + @ExcelProperty("外包合同金额") + private BigDecimal outAmount; + + @Schema(description = "有效合同金额") + @ExcelProperty("有效合同金额") + private BigDecimal validContractAmount; + + @Schema(description = "预估利润率") + @ExcelProperty("预估利润率") + private BigDecimal estimatedProfitMargin; + + @Schema(description = "实际利润率") + @ExcelProperty("实际利润率") + private BigDecimal realProfitMargin; + + @Schema(description = "利润预警") + @ExcelProperty("利润预警") + private String profitWarning; + + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "25375") @ExcelProperty("主键") private Long id; diff --git a/yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/budget/vo/BudgetSaveReqVO.java b/yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/budget/vo/BudgetSaveReqVO.java index f12364657..c269dfab7 100644 --- a/yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/budget/vo/BudgetSaveReqVO.java +++ b/yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/budget/vo/BudgetSaveReqVO.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.pms.controller.admin.budget.vo; +import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; import java.util.*; @@ -10,6 +11,56 @@ import java.math.BigDecimal; @Data public class BudgetSaveReqVO { + @Schema(description = "跟踪项目编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "XS24001") + @ExcelProperty("跟踪项目编号") + private String trackingProjectCode; + + @Schema(description = "项目编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "SJ24001") + @ExcelProperty("项目编号") + private String projectCode; + + @Schema(description = "跟踪项目名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "规划一路道路工程") + @ExcelProperty("跟踪项目名称") + private String trackingProjectName; + + @Schema(description = "项目类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "设计") + @ExcelProperty("项目类型") + private String projectType; + + @Schema(description = "预计合同金额", requiredMode = Schema.RequiredMode.REQUIRED,example = "200.0000") + @ExcelProperty("预计合同金额") + private BigDecimal expectedContractAmount; + + @Schema(description = "暂定结算数") + @ExcelProperty("暂定结算数") + private BigDecimal provisionalSettlement; + + @Schema(description = "包干/审定金额", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("包干/审定金额") + private BigDecimal approvedAmount; + + @Schema(description = "外包合同金额") + @ExcelProperty("外包合同金额") + private BigDecimal outAmount; + + @Schema(description = "有效合同金额") + @ExcelProperty("有效合同金额") + private BigDecimal validContractAmount; + + @Schema(description = "预估利润率") + @ExcelProperty("预估利润率") + private BigDecimal estimatedProfitMargin; + + @Schema(description = "实际利润率") + @ExcelProperty("实际利润率") + private BigDecimal realProfitMargin; + + @Schema(description = "利润预警") + @ExcelProperty("利润预警") + private String profitWarning; + + + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "25375") private Long id; diff --git a/yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/budget/BudgetService.java b/yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/budget/BudgetService.java index 41b5d6da5..5a5453786 100644 --- a/yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/budget/BudgetService.java +++ b/yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/budget/BudgetService.java @@ -1,11 +1,9 @@ package cn.iocoder.yudao.module.pms.service.budget; -import java.util.*; + import jakarta.validation.*; import cn.iocoder.yudao.module.pms.controller.admin.budget.vo.*; -import cn.iocoder.yudao.module.pms.dal.dataobject.budget.BudgetDO; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.pojo.PageParam; /** * 预算管理 Service 接口 @@ -20,14 +18,14 @@ public interface BudgetService { * @param createReqVO 创建信息 * @return 编号 */ - Long createBudget(@Valid BudgetSaveReqVO createReqVO); + Long createBudget(Long loginUserId, @Valid BudgetSaveReqVO createReqVO); /** * 更新预算管理 * * @param updateReqVO 更新信息 */ - void updateBudget(@Valid BudgetSaveReqVO updateReqVO); + void updateBudget(Long loginUserId, @Valid BudgetSaveReqVO updateReqVO); /** * 删除预算管理 @@ -42,7 +40,7 @@ public interface BudgetService { * @param id 编号 * @return 预算管理 */ - BudgetDO getBudget(Long id); + BudgetRespVO getBudget(Long id); /** * 获得预算管理分页 @@ -50,6 +48,6 @@ public interface BudgetService { * @param pageReqVO 分页查询 * @return 预算管理分页 */ - PageResult getBudgetPage(BudgetPageReqVO pageReqVO); + PageResult getBudgetPage(BudgetPageReqVO pageReqVO); } \ No newline at end of file diff --git a/yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/budget/BudgetServiceImpl.java b/yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/budget/BudgetServiceImpl.java index edd22cb1c..bd76a19a4 100644 --- a/yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/budget/BudgetServiceImpl.java +++ b/yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/budget/BudgetServiceImpl.java @@ -1,21 +1,34 @@ package cn.iocoder.yudao.module.pms.service.budget; +import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; +import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; +import cn.iocoder.yudao.module.cms.api.contract.ContractApi; +import cn.iocoder.yudao.module.cms.api.contract.dto.ContractRespDTO; +import cn.iocoder.yudao.module.cms.api.outscontract.OutscontractApi; +import cn.iocoder.yudao.module.pms.api.project.ProjectApi; +import cn.iocoder.yudao.module.pms.api.project.dto.ProjectRespDTO; +import cn.iocoder.yudao.module.pms.dal.dataobject.budgethistory.BudgetHistoryDO; +import cn.iocoder.yudao.module.pms.dal.mysql.budgethistory.BudgetHistoryMapper; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import org.springframework.stereotype.Service; import jakarta.annotation.Resource; import org.springframework.validation.annotation.Validated; -import org.springframework.transaction.annotation.Transactional; +import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.*; import cn.iocoder.yudao.module.pms.controller.admin.budget.vo.*; import cn.iocoder.yudao.module.pms.dal.dataobject.budget.BudgetDO; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.pms.dal.mysql.budget.BudgetMapper; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.cms.enums.ErrorCodeConstants.CONTRACT_NOT_EXISTS; +import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstants.PARAM_NOT_EXISTS; import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_NOT_EXISTS; /** * 预算管理 Service 实现类 @@ -26,24 +39,177 @@ import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstants.*; @Validated public class BudgetServiceImpl implements BudgetService { + /** + * 预算管理流程定义 + */ + public static final String PROCESS_KEY = "budget_init"; + + /** + * 版本 + */ + public static String VERSION = "1"; + @Resource private BudgetMapper budgetMapper; + @Resource + private ProjectApi projectApi; + + @Resource + private ContractApi contractApi; + + @Resource + private OutscontractApi OutscontractApi; + + @Resource + private AdminUserApi adminUserApi; + + @Resource + private BpmProcessInstanceApi processInstanceApi; + + @Resource + private BudgetHistoryMapper budgetHistoryMapper; + @Override - public Long createBudget(BudgetSaveReqVO createReqVO) { + public Long createBudget(Long loginUserId, BudgetSaveReqVO createReqVO) { + + // 校验 用户是否存在 + if (loginUserId == null) { + throw exception(PARAM_NOT_EXISTS); + } + if (createReqVO == null) { + throw exception(PARAM_NOT_EXISTS); + } + String userName = adminUserApi.getUser(loginUserId).getNickname(); + if (userName == null) { + throw exception(USER_NOT_EXISTS); + } + + // 校验 项目,合同是否存在 + Long projectId = createReqVO.getProjectId(); + Long contractId = createReqVO.getContractId(); + projectApi.validProjectExist(projectId); + contractApi.vaildContractExist(contractId); + + ContractRespDTO contract = contractApi.getContract(contractId); + ProjectRespDTO project = projectApi.getProject(projectId); + + // 校验联表的字段是否和所联系的表内容相同 + /** + * 1. 跟踪项目编号 pms直接 + * 2. 项目编号 pms直接 + * 3. 跟踪项目名称 pms直接 + * 4. 项目类型 pms直接 + * 5. 预计合同金额 pms直接 + * 6. 暂定结算数 cms计算 + * 7. 包干/审定金额 cms直接 + * 8. 外包公司金额 cms求和 + */ + String trackingProjectCode = createReqVO.getTrackingProjectCode(); // 跟踪项目编号 + String projectCode = createReqVO.getProjectCode(); // 项目编号 + String trackingProjectName = createReqVO.getTrackingProjectName(); // 跟踪项目名称 + String projectType = createReqVO.getProjectType(); // 项目类型 + BigDecimal expectedContractAmount = createReqVO.getExpectedContractAmount(); // 预计合同金额 + BigDecimal provisionalSettlement = createReqVO.getProvisionalSettlement(); // 暂定结算数 + BigDecimal approvedAmount = createReqVO.getApprovedAmount(); // 包干/审定金额 + BigDecimal outAmount = createReqVO.getOutAmount(); // 外包公司金额 + + String countType = contract.getCountType(); + BigDecimal amount = contract.getAmount(); + BigDecimal bigDecimal = new BigDecimal(String.valueOf(amount)); + BigDecimal mul = new BigDecimal("0.85"); + BigDecimal res = null; + if ("费率合同".equals(countType)) { + res = bigDecimal.multiply(mul); + } else if ("总价合同".equals(countType)) { + res = amount; + } + + BigDecimal outsContractAmount = OutscontractApi.getOutsContractAmount(contractId); + + if (!project.getTrackingCode().equals(trackingProjectCode)) { + throw exception(PARAM_ERROR); + } + if (!project.getCode().equals(projectCode)) { + throw exception(PARAM_ERROR); + } + if (!project.getName().equals(trackingProjectName)) { + throw exception(PARAM_ERROR); + } + if (!project.getType().equals(projectType)) { + throw exception(PARAM_ERROR); + } + if (!Objects.equals(project.getContractAmount(),expectedContractAmount)) { + throw exception(PARAM_ERROR); + } + if (!Objects.equals(provisionalSettlement,res)) { + throw exception(PARAM_ERROR); + } + if (!Objects.equals(contract.getApprovedAmount(),approvedAmount)) { + throw exception(PARAM_ERROR); + } + if (!Objects.equals(outAmount,outsContractAmount)) { + throw exception(PARAM_ERROR); + } + // 插入 BudgetDO budget = BeanUtils.toBean(createReqVO, BudgetDO.class); + BudgetRespVO budgetResp = BeanUtils.toBean(budget, BudgetRespVO.class); + budget.setCreator(userName); + budget.setUpdater(userName); + + // 判断预算是否已存在 + // 获得所有预算后,逐个比较各个字段是否完全一致 + // 查budget通过pms项目id查 + List budgetList = budgetMapper.selectList("project_id", projectId); + List respVOList = BeanUtils.toBean(budgetList, BudgetRespVO.class); + for (BudgetRespVO respVO : respVOList) { + if (respVO.equals(budgetResp)) { + throw exception(BUDGET_ALREADY_EXISTS); + } + } budgetMapper.insert(budget); + + Long budgetId = budget.getId(); + BudgetHistoryDO budgetHistory = BeanUtils.toBean(budget, BudgetHistoryDO.class); + + // 启动流程,同时写入历史预算 + if (createReqVO.getId() == null) { + String processInstanceId = processInstanceApi.createProcessInstance(loginUserId, + new BpmProcessInstanceCreateReqDTO() + .setProcessDefinitionKey(PROCESS_KEY).setBusinessKey(String.valueOf(budgetId))); + + // 写入工作流编号 + budgetHistory.setProcessInstanceId(processInstanceId); + budgetHistory.setBudgetId(budgetId); + + Long count = budgetHistoryMapper.selectCount("project_id", projectId); + if (count < 1) { + budgetHistory.setVersion(VERSION); + } else { + budgetHistory.setVersion(String.valueOf(count+1)); + } + budgetHistory.setProcessStatus("0"); + budgetHistoryMapper.insert(budgetHistory); + } + // 返回 return budget.getId(); } @Override - public void updateBudget(BudgetSaveReqVO updateReqVO) { + public void updateBudget(Long loginUserId, BudgetSaveReqVO updateReqVO) { // 校验存在 validateBudgetExists(updateReqVO.getId()); + projectApi.validProjectExist(updateReqVO.getProjectId()); + contractApi.vaildContractExist(updateReqVO.getContractId()); // 更新 BudgetDO updateObj = BeanUtils.toBean(updateReqVO, BudgetDO.class); + String userName = adminUserApi.getUser(loginUserId).getNickname(); + if (userName == null) { + throw exception(USER_NOT_EXISTS); + } + updateObj.setUpdater(userName); budgetMapper.updateById(updateObj); } @@ -62,13 +228,144 @@ public class BudgetServiceImpl implements BudgetService { } @Override - public BudgetDO getBudget(Long id) { - return budgetMapper.selectById(id); + public BudgetRespVO getBudget(Long id) { + // 校验 + if (id == null) { + throw exception(BUDGET_NOT_EXISTS); + } + + BudgetDO budgetDO = budgetMapper.selectById(id); + if (budgetDO == null) { + throw exception(BUDGET_NOT_EXISTS); + } + + Long projectId = budgetDO.getProjectId(); + if (projectId == null) { + throw exception(BUDGET_NOT_EXISTS); + } + + Long contractId = budgetDO.getContractId(); + if (contractId == null) { + throw exception(BUDGET_NOT_EXISTS); + } + + BudgetRespVO budgetRespVO = BeanUtils.toBean(budgetDO, BudgetRespVO.class); + + /** 查询数据,联表查询 + * 1. 跟踪项目编号 pms直接 √ + * 2. 项目编号 pms直接 √ + * 3. 跟踪项目名称 pms直接 √ + * 4. 项目类型 pms直接 √ + * 5. 预计合同金额 pms直接 √ + * 6. 暂定结算数 cms计算 √ + * 7. 包干/审定金额 cms直接 √ + * 8. 外包公司金额 cms求和 √ + * 9. 有效合同金额 计算公式 √ + * 10. 预估利润率 计算公式 √ + * 11. 实际利润率 计算公式 √ + * 12. 利润预警 计算公式 √ + */ + ProjectRespDTO project = projectApi.getProject(projectId); + ContractRespDTO contract = contractApi.getContract(contractId); + + budgetRespVO.setTrackingProjectCode(project.getTrackingCode()); // 跟踪项目编号 + budgetRespVO.setProjectCode(project.getCode()); // 项目编号 + budgetRespVO.setTrackingProjectName(project.getName()); // 跟踪项目名称 + budgetRespVO.setProjectType(project.getType()); // 项目类型 + budgetRespVO.setExpectedContractAmount(project.getContractAmount()); // 预计合同金额 + + String countType = contract.getCountType(); + BigDecimal amount = contract.getAmount(); + BigDecimal bigDecimal = new BigDecimal(String.valueOf(amount)); + BigDecimal mul = new BigDecimal("0.85"); + BigDecimal res = null; + if ("费率合同".equals(countType)) { + res = bigDecimal.multiply(mul); + } else if ("总价合同".equals(countType)) { + res = amount; + } + budgetRespVO.setProvisionalSettlement(res); // 暂定结算数 + + budgetRespVO.setApprovedAmount(contract.getApprovedAmount()); // 包干/审定金额 + budgetRespVO.setOutAmount(OutscontractApi.getOutsContractAmount(contractId)); // 外包公司金额 + + BigDecimal firstValue = new BigDecimal("0"); + BigDecimal secondValue = new BigDecimal("0"); + if (contract.getApprovedAmount() == null && res != null) { + firstValue = res; + } else if (contract.getApprovedAmount() != null) { + firstValue = contract.getApprovedAmount(); + } else { + firstValue = project.getContractAmount(); + } + if (OutscontractApi.getOutsContractAmount(contractId) == null) { + if (budgetDO.getOutsourcingCosts() != null) { + secondValue = budgetDO.getOutsourcingCosts(); + } + } else { + secondValue = OutscontractApi.getOutsContractAmount(contractId); + } + budgetRespVO.setValidContractAmount(firstValue.subtract(secondValue)); // 有效合同金额 + + BigDecimal estimatedBaseValue = (res == null) ? project.getContractAmount() : res; + if (estimatedBaseValue == null) { + throw exception(PROFIT_MARGIN_ERROR); + } + BigDecimal estimatedNumerator = estimatedBaseValue + .subtract(budgetDO.getOutsourcingCosts() != null ? budgetDO.getOutsourcingCosts() : BigDecimal.ZERO) + .subtract(budgetDO.getLaborCosts() != null ? budgetDO.getLaborCosts() : BigDecimal.ZERO) + .subtract(budgetDO.getProductCosts() != null ? budgetDO.getProductCosts() : BigDecimal.ZERO) + .subtract(budgetDO.getFinancialCosts() != null ? budgetDO.getFinancialCosts() : BigDecimal.ZERO); + budgetRespVO.setEstimatedProfitMargin(estimatedNumerator.divide(estimatedBaseValue, 4 , RoundingMode.HALF_UP)); // 预估利润率 + + BigDecimal realBaseValue = (contract.getApprovedAmount() == null) ? res : contract.getApprovedAmount(); + if (realBaseValue == null) { + throw exception(PROFIT_MARGIN_ERROR); + } + BigDecimal realNumerator = realBaseValue + .subtract(OutscontractApi.getOutsContractAmount(contractId) != null ? OutscontractApi.getOutsContractAmount(contractId) : BigDecimal.ZERO) + .subtract(budgetDO.getAccumulatedLaborCosts() != null ? budgetDO.getAccumulatedLaborCosts() : BigDecimal.ZERO) + .subtract(budgetDO.getAccumulatedProductCosts() != null ? budgetDO.getAccumulatedProductCosts() : BigDecimal.ZERO) + .subtract(budgetDO.getAccumulatedFinancialCosts() != null ? budgetDO.getAccumulatedFinancialCosts() : BigDecimal.ZERO); + BigDecimal realProfitMargin = realNumerator.divide(realBaseValue,4, RoundingMode.HALF_UP); + budgetRespVO.setRealProfitMargin(realProfitMargin); // 实际利润率 + + BigDecimal threshold = new BigDecimal("0.25"); + String profitWarning = (realProfitMargin.compareTo(threshold) < 0) ? "利润预警" : ""; + budgetRespVO.setProfitWarning(profitWarning); // 利润预警 + + return budgetRespVO; } @Override - public PageResult getBudgetPage(BudgetPageReqVO pageReqVO) { - return budgetMapper.selectPage(pageReqVO); + public PageResult getBudgetPage(BudgetPageReqVO pageReqVO) { + // 校验 + if (pageReqVO == null) { + throw exception(PARAM_NOT_EXISTS); + } + + Long projectId = pageReqVO.getProjectId(); + ProjectRespDTO project = projectApi.getProject(projectId); + Long contractId = pageReqVO.getContractId(); + ContractRespDTO contract = contractApi.getContract(contractId); + if (project == null) { + throw exception(PROJECT_NOT_EXISTS); + } + if (contract == null) { + throw exception(CONTRACT_NOT_EXISTS); + } + + PageResult budgetDOPageResult = budgetMapper.selectPage(pageReqVO); + List budgetDOList = budgetDOPageResult.getList(); + List budgetRespVOList = new ArrayList<>(); + for (BudgetDO budgetDO : budgetDOList) { + Long id = budgetDO.getId(); + BudgetRespVO budget = getBudget(id); + budgetRespVOList.add(budget); + } + PageResult pageResult = new PageResult<>(); + pageResult.setList(budgetRespVOList); + return pageResult; } } \ No newline at end of file