package cn.iocoder.yudao.module.srm.service.tender; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.srm.controller.admin.tender.vo.SrmTenderMaterialSaveReqVO; import cn.iocoder.yudao.module.srm.controller.admin.tender.vo.SrmTenderProjectPageReqVO; import cn.iocoder.yudao.module.srm.controller.admin.tender.vo.SrmTenderProjectPartialUpdateReqVO; import cn.iocoder.yudao.module.srm.controller.admin.tender.vo.SrmTenderProjectSaveReqVO; import cn.iocoder.yudao.module.srm.dal.dataobject.SrmBidAwardDO; import cn.iocoder.yudao.module.srm.dal.dataobject.SrmTenderMaterialDO; import cn.iocoder.yudao.module.srm.dal.dataobject.SrmTenderProjectDO; import cn.iocoder.yudao.module.srm.dal.mysql.SrmBidAwardMapper; import cn.iocoder.yudao.module.srm.dal.mysql.SrmTenderBidMapper; import cn.iocoder.yudao.module.srm.dal.mysql.SrmTenderMaterialMapper; import cn.iocoder.yudao.module.srm.dal.mysql.SrmTenderProjectMapper; import cn.iocoder.yudao.module.srm.enums.AwardStatusEnum; import cn.iocoder.yudao.module.srm.enums.ErrorCodeConstants; import cn.iocoder.yudao.module.srm.enums.TenderStatusEnum; import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; import com.mzt.logapi.context.LogRecordContext; import com.mzt.logapi.starter.annotation.LogRecord; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; import static cn.iocoder.yudao.module.srm.enums.LogRecordConstants.*; @Service @Validated public class SrmTenderProjectServiceImpl implements SrmTenderProjectService { @Resource private SrmTenderProjectMapper tenderProjectMapper; @Resource private SrmTenderMaterialMapper tenderMaterialMapper; @Resource private SrmBidAwardMapper bidAwardMapper; @Resource private SrmTenderBidMapper tenderBidMapper; @Override public Long createTenderProject(SrmTenderProjectSaveReqVO createReqVO) { SrmTenderProjectDO project = BeanUtils.toBean(createReqVO, SrmTenderProjectDO.class); project.setTenderStatus(TenderStatusEnum.DRAFT.getCode()); tenderProjectMapper.insert(project); return project.getId(); } @Override @LogRecord(type = LOG_TENDER_TYPE, subType = LOG_TENDER_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", success = LOG_TENDER_UPDATE_SUCCESS) public void updateTenderProject(SrmTenderProjectSaveReqVO updateReqVO) { SrmTenderProjectDO project = validateTenderExists(updateReqVO.getId()); Integer status = project.getTenderStatus(); // 草稿状态:全字段可编辑 if (TenderStatusEnum.canEditFullProject(status)) { SrmTenderProjectDO updateObj = BeanUtils.toBean(updateReqVO, SrmTenderProjectDO.class); updateObj.setTenderStatus(status); // 状态不允许前端传入覆盖 tenderProjectMapper.updateById(updateObj); LogRecordContext.putVariable("tenderName", project.getTenderName()); LogRecordContext.putVariable("oldTenderDesc", project.getTenderDesc()); LogRecordContext.putVariable("newTenderDesc", updateReqVO.getTenderDesc()); LogRecordContext.putVariable("oldQualification", project.getQualificationRequirements()); LogRecordContext.putVariable("newQualification", updateReqVO.getQualificationRequirements()); return; } // 发布中/投标中:仅允许修改招标说明和资质要求 if (TenderStatusEnum.canEditPartialProject(status)) { SrmTenderProjectDO updateObj = new SrmTenderProjectDO(); updateObj.setId(updateReqVO.getId()); updateObj.setTenderDesc(updateReqVO.getTenderDesc()); updateObj.setQualificationRequirements(updateReqVO.getQualificationRequirements()); tenderProjectMapper.updateById(updateObj); LogRecordContext.putVariable("tenderName", project.getTenderName()); LogRecordContext.putVariable("oldTenderDesc", project.getTenderDesc()); LogRecordContext.putVariable("newTenderDesc", updateReqVO.getTenderDesc()); LogRecordContext.putVariable("oldQualification", project.getQualificationRequirements()); LogRecordContext.putVariable("newQualification", updateReqVO.getQualificationRequirements()); return; } // 其他状态:不允许编辑 throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_PROJECT_LOCKED); } @Override public void deleteTenderProject(Long id) { SrmTenderProjectDO project = validateTenderExists(id); if (!TenderStatusEnum.DRAFT.getCode().equals(project.getTenderStatus())) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_STATUS_NOT_DRAFT); } // 检查是否已有投标数据 if (tenderBidMapper.countByTenderProjectId(id) > 0) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_HAS_BIDS_CANNOT_DELETE); } tenderMaterialMapper.deleteByTenderProjectId(id); tenderProjectMapper.deleteById(id); } @Override public SrmTenderProjectDO getTenderProject(Long id) { SrmTenderProjectDO project = tenderProjectMapper.selectById(id); if (project != null) { SrmBidAwardDO award = bidAwardMapper.selectByTenderProjectId(id); if (award != null) { project.setAwardId(award.getId()); project.setPurchaseOrderNo(award.getPurchaseOrderNo()); } } return project; } @Override public PageResult getTenderProjectPage(SrmTenderProjectPageReqVO pageReqVO) { PageResult pageResult = tenderProjectMapper.selectPage(pageReqVO); // 批量查询定标信息,填充 awardId 和 purchaseOrderNo List projectIds = pageResult.getList().stream() .map(SrmTenderProjectDO::getId).collect(Collectors.toList()); if (!projectIds.isEmpty()) { List awards = bidAwardMapper.selectListByTenderProjectIds(projectIds); Map awardMap = awards.stream().collect(Collectors.toMap( SrmBidAwardDO::getTenderProjectId, Function.identity(), (a, b) -> a)); pageResult.getList().forEach(project -> { SrmBidAwardDO award = awardMap.get(project.getId()); if (award != null) { project.setAwardId(award.getId()); project.setPurchaseOrderNo(award.getPurchaseOrderNo()); // 防御:如果定标已生成订单但项目状态未更新,同步状态 if (AwardStatusEnum.ORDER_GENERATED.getCode().equals(award.getAwardStatus())) { project.setTenderStatus(TenderStatusEnum.CLOSED.getCode()); } } }); } return pageResult; } @Override public void publishTender(Long id) { SrmTenderProjectDO project = validateTenderExists(id); if (!TenderStatusEnum.DRAFT.getCode().equals(project.getTenderStatus())) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_STATUS_NOT_DRAFT); } project.setTenderStatus(TenderStatusEnum.PUBLISHED.getCode()); tenderProjectMapper.updateById(project); } @Override public void closeTender(Long id) { SrmTenderProjectDO project = validateTenderExists(id); if (TenderStatusEnum.CLOSED.getCode().equals(project.getTenderStatus())) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_STATUS_ALREADY_CLOSED); } // 草稿状态不允许直接关闭 if (TenderStatusEnum.DRAFT.getCode().equals(project.getTenderStatus())) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_PROJECT_LOCKED); } project.setTenderStatus(TenderStatusEnum.CLOSED.getCode()); tenderProjectMapper.updateById(project); } @Override public void startBidding(Long id) { SrmTenderProjectDO project = validateTenderExists(id); if (!TenderStatusEnum.PUBLISHED.getCode().equals(project.getTenderStatus())) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_STATUS_NOT_PUBLISHED); } project.setTenderStatus(TenderStatusEnum.BIDDING.getCode()); tenderProjectMapper.updateById(project); } @Override public void startEvaluation(Long id) { SrmTenderProjectDO project = validateTenderExists(id); if (!TenderStatusEnum.BIDDING.getCode().equals(project.getTenderStatus())) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_STATUS_NOT_BIDDING); } project.setTenderStatus(TenderStatusEnum.EVALUATING.getCode()); tenderProjectMapper.updateById(project); } @Override @LogRecord(type = LOG_TENDER_TYPE, subType = LOG_TENDER_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", success = LOG_TENDER_UPDATE_SUCCESS) public void updateTenderProjectPartial(SrmTenderProjectPartialUpdateReqVO updateReqVO) { SrmTenderProjectDO project = validateTenderExists(updateReqVO.getId()); if (!TenderStatusEnum.canEditPartialProject(project.getTenderStatus())) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_PROJECT_LOCKED); } SrmTenderProjectDO updateObj = new SrmTenderProjectDO(); updateObj.setId(updateReqVO.getId()); updateObj.setTenderDesc(updateReqVO.getTenderDesc()); updateObj.setQualificationRequirements(updateReqVO.getQualificationRequirements()); tenderProjectMapper.updateById(updateObj); LogRecordContext.putVariable("tenderName", project.getTenderName()); LogRecordContext.putVariable("oldTenderDesc", project.getTenderDesc()); LogRecordContext.putVariable("newTenderDesc", updateReqVO.getTenderDesc()); LogRecordContext.putVariable("oldQualification", project.getQualificationRequirements()); LogRecordContext.putVariable("newQualification", updateReqVO.getQualificationRequirements()); } // ========== 物料子表 ========== @Override public void createMaterial(SrmTenderMaterialSaveReqVO createReqVO) { SrmTenderProjectDO project = validateTenderExists(createReqVO.getTenderProjectId()); if (!TenderStatusEnum.canEditMaterial(project.getTenderStatus())) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_MATERIAL_LOCKED); } SrmTenderMaterialDO material = BeanUtils.toBean(createReqVO, SrmTenderMaterialDO.class); tenderMaterialMapper.insert(material); } @Override public void updateMaterial(SrmTenderMaterialSaveReqVO updateReqVO) { SrmTenderMaterialDO existing = tenderMaterialMapper.selectById(updateReqVO.getId()); if (existing != null) { SrmTenderProjectDO project = tenderProjectMapper.selectById(existing.getTenderProjectId()); if (project != null && !TenderStatusEnum.canEditMaterial(project.getTenderStatus())) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_MATERIAL_LOCKED); } } SrmTenderMaterialDO updateObj = BeanUtils.toBean(updateReqVO, SrmTenderMaterialDO.class); tenderMaterialMapper.updateById(updateObj); } @Override public void deleteMaterial(Long id) { SrmTenderMaterialDO material = tenderMaterialMapper.selectById(id); if (material != null) { SrmTenderProjectDO project = tenderProjectMapper.selectById(material.getTenderProjectId()); if (project != null && !TenderStatusEnum.canEditMaterial(project.getTenderStatus())) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_MATERIAL_LOCKED); } } tenderMaterialMapper.deleteById(id); } @Override public List getMaterialList(Long tenderProjectId) { return tenderMaterialMapper.selectListByTenderProjectId(tenderProjectId); } private SrmTenderProjectDO validateTenderExists(Long id) { SrmTenderProjectDO project = tenderProjectMapper.selectById(id); if (project == null) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_NOT_EXISTS); } return project; } }