huminmin
7 天以前 0fdd0bf60b7d98d21c9b5ff95bb55f0fa6495007
yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/tender/SrmTenderBidServiceImpl.java
@@ -5,6 +5,7 @@
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.dataobject.SrmTenderProjectDO;
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;
@@ -13,6 +14,8 @@
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.transaction.annotation.Transactional;
@@ -20,6 +23,8 @@
import java.time.LocalDateTime;
import java.util.List;
import static cn.iocoder.yudao.module.srm.enums.LogRecordConstants.*;
/**
 * SRM 投标管理 Service 实现类
@@ -44,9 +49,15 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    @LogRecord(type = LOG_BID_TYPE, subType = LOG_BID_CREATE_SUB_TYPE,
            bizNo = "{{#createReqVO.bidNo}}", success = LOG_BID_CREATE_SUCCESS)
    public Long createBid(SrmTenderBidSaveReqVO createReqVO) {
        // 校验招标项目是否存在且状态正确
        validateTenderStatus(createReqVO.getTenderProjectId());
        // 校验招标项目状态(PUBLISHED/BIDDING 才允许投标)
        SrmTenderProjectDO project = validateTenderStatus(createReqVO.getTenderProjectId());
        // 检查投标截止时间
        if (project.getEndTime() != null && LocalDateTime.now().isAfter(project.getEndTime())) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_END_TIME_PASSED);
        }
        // 校验供应商是否已通过准入审批
        if (!supplierApplyMapper.existsApprovedBySupplierId(createReqVO.getSupplierId())) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.BID_SUPPLIER_NOT_APPROVED);
@@ -64,6 +75,8 @@
        bid.setBidStatus(BidStatusEnum.REGISTERED.getCode());
        bid.setBidTime(LocalDateTime.now());
        tenderBidMapper.insert(bid);
        LogRecordContext.putVariable("bidNo", bid.getBidNo());
        LogRecordContext.putVariable("tenderName", project.getTenderName());
        return bid.getId();
    }
@@ -79,20 +92,35 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    @LogRecord(type = LOG_BID_TYPE, subType = LOG_BID_WITHDRAW_SUB_TYPE,
            bizNo = "{{#id}}", success = LOG_BID_WITHDRAW_SUCCESS)
    public void withdrawBid(Long id) {
        SrmTenderBidDO bid = validateBidExists(id);
        // 检查招标项目状态:仅 PUBLISHED/BIDDING 允许撤标
        SrmTenderProjectDO project = tenderProjectMapper.selectById(bid.getTenderProjectId());
        if (project == null || !TenderStatusEnum.canCreateOrUpdateQuote(project.getTenderStatus())) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_BID_FORBIDDEN_WITHDRAW);
        }
        bid.setBidStatus(BidStatusEnum.WITHDRAWN.getCode());
        tenderBidMapper.updateById(bid);
        // 删除报价
        supplierQuoteMapper.deleteByBidId(id);
        LogRecordContext.putVariable("bidNo", bid.getBidNo());
    }
    // ========== 报价管理 ==========
    @Override
    @LogRecord(type = LOG_QUOTE_TYPE, subType = LOG_QUOTE_CREATE_SUB_TYPE,
            bizNo = "{{#createReqVO.bidId}}", success = LOG_QUOTE_CREATE_SUCCESS)
    public Long createQuote(SrmSupplierQuoteSaveReqVO createReqVO) {
        // 校验投标状态(撤标后不允许报价)
        SrmTenderBidDO bid = validateBidNotWithdrawn(createReqVO.getBidId());
        // 校验招标项目状态:仅 PUBLISHED/BIDDING 允许报价
        SrmTenderProjectDO project = tenderProjectMapper.selectById(bid.getTenderProjectId());
        if (project == null || !TenderStatusEnum.canCreateOrUpdateQuote(project.getTenderStatus())) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_QUOTE_FORBIDDEN);
        }
        // 校验同一投标下物料不可重复报价
        if (supplierQuoteMapper.existsByBidAndMaterial(createReqVO.getBidId(), createReqVO.getTenderMaterialId())) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.QUOTE_MATERIAL_DUPLICATE);
@@ -108,7 +136,12 @@
    @Override
    public void updateQuote(SrmSupplierQuoteSaveReqVO updateReqVO) {
        // 校验投标状态(撤标后不允许报价)
        validateBidNotWithdrawn(updateReqVO.getBidId());
        SrmTenderBidDO bid = validateBidNotWithdrawn(updateReqVO.getBidId());
        // 校验招标项目状态:仅 PUBLISHED/BIDDING 允许报价
        SrmTenderProjectDO project = tenderProjectMapper.selectById(bid.getTenderProjectId());
        if (project == null || !TenderStatusEnum.canCreateOrUpdateQuote(project.getTenderStatus())) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_QUOTE_FORBIDDEN);
        }
        // 校验同一投标下物料不可重复报价(排除自身)
        SrmSupplierQuoteDO existing = supplierQuoteMapper.selectById(updateReqVO.getId());
        if (existing != null && !existing.getTenderMaterialId().equals(updateReqVO.getTenderMaterialId())) {
@@ -143,9 +176,14 @@
        return bid;
    }
    private void validateTenderStatus(Long tenderProjectId) {
        if (tenderProjectMapper.selectById(tenderProjectId) == null) {
    private SrmTenderProjectDO validateTenderStatus(Long tenderProjectId) {
        SrmTenderProjectDO project = tenderProjectMapper.selectById(tenderProjectId);
        if (project == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_NOT_EXISTS);
        }
        if (!TenderStatusEnum.canCreateBid(project.getTenderStatus())) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.TENDER_BID_FORBIDDEN);
        }
        return project;
    }
}