package cn.iocoder.yudao.module.srm.service.tender; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.srm.controller.admin.tender.vo.SrmSupplierQuoteSaveReqVO; import cn.iocoder.yudao.module.srm.controller.admin.tender.vo.SrmTenderBidSaveReqVO; import cn.iocoder.yudao.module.srm.dal.dataobject.SrmSupplierQuoteDO; import cn.iocoder.yudao.module.srm.dal.dataobject.SrmTenderBidDO; import cn.iocoder.yudao.module.srm.dal.mysql.SrmSupplierApplyMapper; import cn.iocoder.yudao.module.srm.dal.mysql.SrmSupplierQuoteMapper; import cn.iocoder.yudao.module.srm.dal.mysql.SrmTenderBidMapper; import cn.iocoder.yudao.module.srm.dal.mysql.SrmTenderProjectMapper; import cn.iocoder.yudao.module.srm.enums.BidStatusEnum; 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 jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.time.LocalDateTime; import java.util.List; /** * SRM 投标管理 Service 实现类 */ @Service @Validated public class SrmTenderBidServiceImpl implements SrmTenderBidService { @Resource private SrmTenderBidMapper tenderBidMapper; @Resource private SrmSupplierQuoteMapper supplierQuoteMapper; @Resource private SrmTenderProjectMapper tenderProjectMapper; @Resource private SrmSupplierApplyMapper supplierApplyMapper; // ========== 投标管理 ========== @Override @Transactional(rollbackFor = Exception.class) public Long createBid(SrmTenderBidSaveReqVO createReqVO) { // 校验招标项目是否存在且状态正确 validateTenderStatus(createReqVO.getTenderProjectId()); // 校验供应商是否已通过准入审批 if (!supplierApplyMapper.existsApprovedBySupplierId(createReqVO.getSupplierId())) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.BID_SUPPLIER_NOT_APPROVED); } // 校验供应商是否已参与投标 SrmTenderBidDO existing = tenderBidMapper.selectByTenderAndSupplier(createReqVO.getTenderProjectId(), createReqVO.getSupplierId()); if (existing != null) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.BID_SUPPLIER_EXISTS); } SrmTenderBidDO bid = BeanUtils.toBean(createReqVO, SrmTenderBidDO.class); bid.setBidStatus(BidStatusEnum.REGISTERED.getCode()); bid.setBidTime(LocalDateTime.now()); tenderBidMapper.insert(bid); return bid.getId(); } @Override public SrmTenderBidDO getBid(Long id) { return tenderBidMapper.selectById(id); } @Override public List getBidListByProject(Long tenderProjectId) { return tenderBidMapper.selectListByTenderProjectId(tenderProjectId); } @Override @Transactional(rollbackFor = Exception.class) public void withdrawBid(Long id) { SrmTenderBidDO bid = validateBidExists(id); bid.setBidStatus(BidStatusEnum.WITHDRAWN.getCode()); tenderBidMapper.updateById(bid); // 删除报价 supplierQuoteMapper.deleteByBidId(id); } // ========== 报价管理 ========== @Override public Long createQuote(SrmSupplierQuoteSaveReqVO createReqVO) { // 校验投标状态(撤标后不允许报价) SrmTenderBidDO bid = validateBidNotWithdrawn(createReqVO.getBidId()); // 校验同一投标下物料不可重复报价 if (supplierQuoteMapper.existsByBidAndMaterial(createReqVO.getBidId(), createReqVO.getTenderMaterialId())) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.QUOTE_MATERIAL_DUPLICATE); } SrmSupplierQuoteDO quote = BeanUtils.toBean(createReqVO, SrmSupplierQuoteDO.class); // 从投标记录中获取招标项目ID和供应商ID,避免前端遗漏导致数据库约束失败 quote.setTenderProjectId(bid.getTenderProjectId()); quote.setSupplierId(bid.getSupplierId()); supplierQuoteMapper.insert(quote); return quote.getId(); } @Override public void updateQuote(SrmSupplierQuoteSaveReqVO updateReqVO) { // 校验投标状态(撤标后不允许报价) validateBidNotWithdrawn(updateReqVO.getBidId()); // 校验同一投标下物料不可重复报价(排除自身) SrmSupplierQuoteDO existing = supplierQuoteMapper.selectById(updateReqVO.getId()); if (existing != null && !existing.getTenderMaterialId().equals(updateReqVO.getTenderMaterialId())) { if (supplierQuoteMapper.existsByBidAndMaterial(updateReqVO.getBidId(), updateReqVO.getTenderMaterialId())) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.QUOTE_MATERIAL_DUPLICATE); } } SrmSupplierQuoteDO updateObj = BeanUtils.toBean(updateReqVO, SrmSupplierQuoteDO.class); supplierQuoteMapper.updateById(updateObj); } @Override public List getQuoteList(Long bidId) { return supplierQuoteMapper.selectListByBidId(bidId); } // ========== 校验方法 ========== private SrmTenderBidDO validateBidExists(Long id) { SrmTenderBidDO bid = tenderBidMapper.selectById(id); if (bid == null) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.BID_NOT_EXISTS); } return bid; } private SrmTenderBidDO validateBidNotWithdrawn(Long bidId) { SrmTenderBidDO bid = validateBidExists(bidId); if (BidStatusEnum.WITHDRAWN.getCode().equals(bid.getBidStatus())) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.BID_WITHDRAWN_CANNOT_QUOTE); } return bid; } private void validateTenderStatus(Long tenderProjectId) { if (tenderProjectMapper.selectById(tenderProjectId) == null) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_NOT_EXISTS); } } }