package cn.iocoder.yudao.module.crm.service.quotation; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.module.crm.controller.admin.quotation.vo.CrmSaleQuotationImportExcelVO; import cn.iocoder.yudao.module.crm.controller.admin.quotation.vo.CrmSaleQuotationSaveReqVO; import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; import cn.iocoder.yudao.module.crm.dal.dataobject.quotation.CrmSaleQuotationDO; import cn.iocoder.yudao.module.crm.dal.mysql.customer.CrmCustomerMapper; import cn.iocoder.yudao.module.crm.dal.mysql.quotation.CrmSaleQuotationMapper; import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi; import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.util.*; @Service public class CrmSaleQuotationImportService { @Resource private CrmCustomerMapper customerMapper; @Resource private CrmSaleQuotationMapper quotationMapper; @Resource private MdmItemApi itemApi; @Resource private CrmSaleQuotationService quotationService; public Map importRows(List rows, Long userId) { Map> groups = new LinkedHashMap<>(); int rowNumber = 1; for (CrmSaleQuotationImportExcelVO row : rows) { rowNumber++; if (row == null) continue; if (StrUtil.isBlank(row.getName()) && StrUtil.isBlank(row.getCustomerName()) && StrUtil.isBlank(row.getItemCode())) continue; if (StrUtil.isBlank(row.getName()) || StrUtil.isBlank(row.getCustomerName())) { throw new IllegalArgumentException("第" + rowNumber + "行报价名称和客户名称不能为空"); } String key = row.getCustomerName().trim() + " / " + row.getName().trim(); groups.computeIfAbsent(key, ignored -> new ArrayList<>()).add(row); } if (groups.isEmpty()) throw new IllegalArgumentException("导入数据不能为空"); List created = new ArrayList<>(); Map failures = new LinkedHashMap<>(); groups.forEach((key, group) -> { try { CrmSaleQuotationImportExcelVO first = group.get(0); CrmCustomerDO customer = customerMapper.selectByCustomerName(first.getCustomerName().trim()); if (customer == null) throw new IllegalArgumentException("客户不存在:" + first.getCustomerName()); if (quotationMapper.selectCount(new LambdaQueryWrapper() .eq(CrmSaleQuotationDO::getCustomerId, customer.getId()).eq(CrmSaleQuotationDO::getName, first.getName().trim())) > 0) { throw new IllegalArgumentException("该客户已有同名报价单,请勿重复导入"); } CrmSaleQuotationSaveReqVO req = new CrmSaleQuotationSaveReqVO(); req.setName(first.getName().trim()); req.setCustomerId(customer.getId()); req.setOwnerUserId(userId); req.setQuotationTime(first.getQuotationTime()); req.setValidUntil(first.getValidUntil()); req.setDiscountPercent(first.getDiscountPercent() == null ? BigDecimal.ZERO : first.getDiscountPercent()); if (req.getDiscountPercent().signum() < 0 || req.getDiscountPercent().compareTo(new BigDecimal("100")) > 0) throw new IllegalArgumentException("折扣须在 0 到 100 之间"); if (req.getQuotationTime() != null && req.getValidUntil() != null && req.getValidUntil().isBefore(req.getQuotationTime())) throw new IllegalArgumentException("有效期不能早于报价日期"); List items = new ArrayList<>(); for (CrmSaleQuotationImportExcelVO row : group) { if (row.getQuotationTime() != null && !row.getQuotationTime().equals(first.getQuotationTime()) || row.getValidUntil() != null && !row.getValidUntil().equals(first.getValidUntil()) || row.getDiscountPercent() != null && (first.getDiscountPercent() == null || row.getDiscountPercent().compareTo(first.getDiscountPercent()) != 0)) throw new IllegalArgumentException("同一报价单的日期和折扣必须一致"); if (StrUtil.isBlank(row.getItemCode()) || row.getPrice() == null || row.getPrice().signum() < 0 || row.getCount() == null || row.getCount().signum() <= 0) throw new IllegalArgumentException("物料编码、非负单价和大于零的数量不能为空"); if (row.getTaxPercent() != null && (row.getTaxPercent().signum() < 0 || row.getTaxPercent().compareTo(new BigDecimal("100")) > 0)) throw new IllegalArgumentException("税率须在 0 到 100 之间"); MdmItemRespDTO item = itemApi.getItemByCode(row.getItemCode().trim()).getCheckedData(); if (item == null) throw new IllegalArgumentException("物料不存在:" + row.getItemCode()); CrmSaleQuotationSaveReqVO.Item detail = new CrmSaleQuotationSaveReqVO.Item(); detail.setItemId(item.getId()); detail.setQuotationPrice(row.getPrice()); detail.setCount(row.getCount()); detail.setTaxPercent(row.getTaxPercent()); detail.setRemark(row.getRemark()); items.add(detail); } req.setItems(items); quotationService.createSaleQuotation(req, userId); created.add(key); } catch (ServiceException | IllegalArgumentException ex) { failures.put(key, ex.getMessage()); } }); Map result = new LinkedHashMap<>(); result.put("createQuotationNames", created); result.put("failureQuotationNames", failures); return result; } }