package cn.iocoder.yudao.module.srm.service.supplier; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.srm.controller.admin.supplier.vo.SrmSupplierImportExcelVO; import cn.iocoder.yudao.module.srm.controller.admin.supplier.vo.SrmSupplierImportRespVO; import cn.iocoder.yudao.module.srm.controller.admin.supplier.vo.SrmSupplierPageReqVO; import cn.iocoder.yudao.module.srm.controller.admin.supplier.vo.SrmSupplierSaveReqVO; import cn.iocoder.yudao.module.srm.dal.dataobject.*; import cn.iocoder.yudao.module.srm.dal.mysql.SrmBidAwardMapper; import cn.iocoder.yudao.module.srm.dal.mysql.SrmBidEvaluationMapper; import cn.iocoder.yudao.module.srm.dal.mysql.SrmSupplierApplyMapper; import cn.iocoder.yudao.module.srm.dal.mysql.SrmSupplierCategoryMapper; import cn.iocoder.yudao.module.srm.dal.mysql.SrmSupplierContactMapper; import cn.iocoder.yudao.module.srm.dal.mysql.SrmSupplierCertificateMapper; import cn.iocoder.yudao.module.srm.dal.mysql.SrmSupplierMapper; import cn.iocoder.yudao.module.srm.dal.mysql.SrmTenderBidMapper; import cn.iocoder.yudao.module.srm.enums.ErrorCodeConstants; import cn.iocoder.yudao.module.srm.enums.SupplierTypeEnum; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @Service @Validated public class SrmSupplierServiceImpl implements SrmSupplierService { @Resource private SrmSupplierMapper supplierMapper; @Resource private SrmSupplierContactMapper supplierContactMapper; @Resource private SrmSupplierCategoryMapper supplierCategoryMapper; @Resource private SrmSupplierApplyMapper supplierApplyMapper; @Resource private SrmSupplierCertificateMapper supplierCertificateMapper; @Resource private SrmTenderBidMapper tenderBidMapper; @Resource private SrmBidEvaluationMapper bidEvaluationMapper; @Resource private SrmBidAwardMapper bidAwardMapper; @Override public Long createSupplier(SrmSupplierSaveReqVO createReqVO) { // 校验供应商编码唯一性 validateCodeUnique(createReqVO.getCode(), null); // 插入 SrmSupplierDO supplier = BeanUtils.toBean(createReqVO, SrmSupplierDO.class); supplierMapper.insert(supplier); return supplier.getId(); } @Override public void updateSupplier(SrmSupplierSaveReqVO updateReqVO) { // 校验存在性 validateSupplierExists(updateReqVO.getId()); // 校验编码唯一性 validateCodeUnique(updateReqVO.getCode(), updateReqVO.getId()); // 更新 SrmSupplierDO updateObj = BeanUtils.toBean(updateReqVO, SrmSupplierDO.class); supplierMapper.updateById(updateObj); } @Override @Transactional(rollbackFor = Exception.class) public void deleteSupplier(Long id) { // 校验存在性 validateSupplierExists(id); // 关联数据存在时,不允许删除 validateNoReference(id); // 可直接清理的关联数据 supplierContactMapper.deleteBySupplierId(id); supplierCategoryMapper.deleteBySupplierId(id); // 逻辑删除 supplierMapper.deleteById(id); } @Override public SrmSupplierDO getSupplier(Long id) { return supplierMapper.selectById(id); } @Override public PageResult getSupplierPage(SrmSupplierPageReqVO pageReqVO) { return supplierMapper.selectPage(pageReqVO); } @Override @Transactional(rollbackFor = Exception.class) public SrmSupplierImportRespVO importSupplierList(List importList, Boolean updateSupport) { if (CollUtil.isEmpty(importList)) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.SUPPLIER_IMPORT_LIST_IS_EMPTY); } SrmSupplierImportRespVO respVO = SrmSupplierImportRespVO.builder() .createList(new ArrayList<>()) .updateList(new ArrayList<>()) .failureList(new LinkedHashMap<>()) .build(); // 逐行导入:单行失败记录到 failureList,不影响其它行 for (SrmSupplierImportExcelVO importVO : importList) { String code = StrUtil.trim(importVO.getCode()); String name = StrUtil.trim(importVO.getName()); if (StrUtil.isBlank(code) || StrUtil.isBlank(name)) { respVO.getFailureList().put(StrUtil.blankToDefault(name, code), "供应商编码和供应商名称不能为空"); continue; } SrmSupplierSaveReqVO saveReqVO = toSaveReqVO(importVO); try { SrmSupplierDO existByCode = supplierMapper.selectByCode(code); if (existByCode != null) { if (!Boolean.TRUE.equals(updateSupport)) { respVO.getFailureList().put(name, "供应商编码已存在"); continue; } saveReqVO.setId(existByCode.getId()); updateSupplier(saveReqVO); respVO.getUpdateList().add(name); } else { createSupplier(saveReqVO); respVO.getCreateList().add(name); } } catch (Exception ex) { // 单条失败,记录并继续 String reason = ex instanceof ServiceException ? ((ServiceException) ex).getMessage() : ex.getMessage(); respVO.getFailureList().put(name, reason == null ? "导入失败" : reason); } } return respVO; } @Override public List getSupplierSimpleList() { return supplierMapper.selectApprovedList(); } @Override public List getSupplierAllList() { return supplierMapper.selectList(new LambdaQueryWrapperX() // 过滤停用供应商,保留未设置状态与启用状态的档案供应商(仅用于招投标场景) .and(w -> w.isNull(SrmSupplierDO::getStatus) .or() .ne(SrmSupplierDO::getStatus, CommonStatusEnum.DISABLE.getStatus())) .orderByAsc(SrmSupplierDO::getId)); } @Override public List getSupplierList(Collection ids) { if (CollUtil.isEmpty(ids)) { return Collections.emptyList(); } return supplierMapper.selectBatchIds(ids); } // ========== 导入辅助方法 ========== /** * 导入 VO -> 保存 VO,复用 create/update 逻辑; * 类型支持中文名称或编码(1~4),状态留空默认启用 */ private SrmSupplierSaveReqVO toSaveReqVO(SrmSupplierImportExcelVO importVO) { SrmSupplierSaveReqVO saveReqVO = new SrmSupplierSaveReqVO(); saveReqVO.setCode(StrUtil.trim(importVO.getCode())); saveReqVO.setName(StrUtil.trim(importVO.getName())); saveReqVO.setShortName(StrUtil.trimToNull(importVO.getShortName())); saveReqVO.setType(parseTypeCode(importVO.getType())); saveReqVO.setCompanyNature(StrUtil.trimToNull(importVO.getCompanyNature())); saveReqVO.setRegisteredCapital(importVO.getRegisteredCapital()); saveReqVO.setBusinessLicenseNo(StrUtil.trimToNull(importVO.getBusinessLicenseNo())); saveReqVO.setTaxNo(StrUtil.trimToNull(importVO.getTaxNo())); saveReqVO.setLegalPerson(StrUtil.trimToNull(importVO.getLegalPerson())); saveReqVO.setAddress(StrUtil.trimToNull(importVO.getAddress())); saveReqVO.setWebsite(StrUtil.trimToNull(importVO.getWebsite())); saveReqVO.setContactName(StrUtil.trimToNull(importVO.getContactName())); saveReqVO.setContactMobile(StrUtil.trimToNull(importVO.getContactMobile())); saveReqVO.setContactEmail(StrUtil.trimToNull(importVO.getContactEmail())); saveReqVO.setBankName(StrUtil.trimToNull(importVO.getBankName())); saveReqVO.setBankAccount(StrUtil.trimToNull(importVO.getBankAccount())); saveReqVO.setStatus(importVO.getStatus() != null ? importVO.getStatus() : CommonStatusEnum.ENABLE.getStatus()); saveReqVO.setRemark(StrUtil.trimToNull(importVO.getRemark())); return saveReqVO; } /** * 供应商类型解析:中文名称或编码(1~4)均转换为编码字符串; * 无法识别时保留原值,避免导入被阻塞 */ private String parseTypeCode(String type) { String t = StrUtil.trimToNull(type); if (t == null) { return null; } for (SupplierTypeEnum e : SupplierTypeEnum.values()) { if (t.equalsIgnoreCase(e.getName()) || t.equals(String.valueOf(e.getCode()))) { return String.valueOf(e.getCode()); } } // 兼容 Excel 数字单元格被读成 "1.0" 等带小数形式 try { BigDecimal bd = new BigDecimal(t); if (bd.stripTrailingZeros().scale() <= 0) { int i = bd.intValueExact(); if (i >= 1 && i <= 4) { return String.valueOf(i); } } } catch (NumberFormatException ignored) { // 忽略:保持原值 } return t; } // ========== 校验方法 ========== private void validateSupplierExists(Long id) { if (supplierMapper.selectById(id) == null) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.SUPPLIER_NOT_EXISTS); } } private void validateCodeUnique(String code, Long id) { SrmSupplierDO existing = supplierMapper.selectByCode(code); if (existing != null && !existing.getId().equals(id)) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.SUPPLIER_CODE_EXISTS); } } private void validateNoReference(Long id) { boolean hasReference = supplierApplyMapper.existsApprovedBySupplierId(id) || supplierCertificateMapper.selectCount(SrmSupplierCertificateDO::getSupplierId, id) > 0 || tenderBidMapper.selectCount(SrmTenderBidDO::getSupplierId, id) > 0 || bidEvaluationMapper.selectCount(SrmBidEvaluationDO::getSupplierId, id) > 0 || bidAwardMapper.selectCount(SrmBidAwardDO::getSupplierId, id) > 0; if (hasReference) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.SUPPLIER_EXISTS_REFERENCE); } } }