yudao-module-crm/pom.xml
@@ -93,5 +93,11 @@ <groupId>cn.iocoder.boot</groupId> <artifactId>yudao-spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>cn.iocoder.boot</groupId> <artifactId>yudao-module-mdm</artifactId> <version>2026.06-jdk25-SNAPSHOT</version> <scope>compile</scope> </dependency> </dependencies> </project> yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java
@@ -19,7 +19,8 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractProductDO; import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi; import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO; import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; @@ -69,9 +70,10 @@ @Resource private CrmBusinessService businessService; @Resource private CrmProductService productService; @Resource private CrmReceivableService receivableService; @Resource private MdmItemApi mdmItemApi; @Resource private AdminUserApi adminUserApi; @@ -118,12 +120,12 @@ CrmContractRespVO contractVO = buildContractDetailList(singletonList(contract)).get(0); // 拼接产品项 List<CrmContractProductDO> businessProducts = contractService.getContractProductListByContractId(contractVO.getId()); Map<Long, CrmProductDO> productMap = productService.getProductMap( convertSet(businessProducts, CrmContractProductDO::getProductId)); Map<Long, MdmItemRespDTO> itemMap = mdmItemApi.getItemMap( convertSet(businessProducts, CrmContractProductDO::getItemId)); contractVO.setProducts(BeanUtils.toBean(businessProducts, CrmContractRespVO.Product.class, businessProductVO -> MapUtils.findAndThen(productMap, businessProductVO.getProductId(), product -> businessProductVO.setProductName(product.getName()) .setProductNo(product.getNo()).setProductUnit(product.getUnit())))); MapUtils.findAndThen(itemMap, businessProductVO.getItemId(), item -> businessProductVO.setItemCode(item.getCode()) .setItemName(item.getName()).setItemBarCode(item.getBarCode())))); return contractVO; } yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/quotation/CrmSaleQuotationController.java
@@ -38,8 +38,10 @@ import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; @Tag(name = "管理后台 - CRM 销售报价单") @@ -164,8 +166,10 @@ // 1. 构建物料明细 if (CollUtil.isNotEmpty(productList)) { Map<Long, MdmItemRespDTO> itemMap = mdmItemApi.getItemMap(convertSet(productList, CrmSaleQuotationProductDO::getItemId)); Map<Long, MdmUnitMeasureRespDTO> unitMap = mdmUnitMeasureApi.getUnitMeasureMap( convertSet(productList, CrmSaleQuotationProductDO::getItemUnitId)); Map<Long, MdmUnitMeasureRespDTO> unitMap = convertMap( mdmUnitMeasureApi.getUnitMeasureList( convertSet(productList, CrmSaleQuotationProductDO::getItemUnitId)).getCheckedData(), MdmUnitMeasureRespDTO::getId); respVO.setItems(BeanUtils.toBean(productList, CrmSaleQuotationRespVO.Item.class, item -> { MdmItemRespDTO mdmItem = itemMap.get(item.getItemId()); if (mdmItem != null) { yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java
@@ -52,6 +52,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; @@ -219,7 +220,7 @@ private List<CrmContractProductDO> validateContractProducts(List<CrmContractSaveReqVO.Product> list) { // 1. 校验物料存在且启用 List<Long> itemIds = convertSet(list, CrmContractSaveReqVO.Product::getItemId); Set<Long> itemIds = convertSet(list, CrmContractSaveReqVO.Product::getItemId); Map<Long, MdmItemRespDTO> itemMap = mdmItemApi.getItemMap(itemIds); // 2. 转化为 CrmContractProductDO 列表 return convertList(list, o -> BeanUtils.toBean(o, CrmContractProductDO.class, item -> { @@ -468,7 +469,7 @@ List<ErpSaleOrderCreateReqDTO.Item> items = contractProducts.stream() .map(cp -> { ErpSaleOrderCreateReqDTO.Item item = new ErpSaleOrderCreateReqDTO.Item(); item.setItemId(cp.getItemId()); item.setProductId(cp.getItemId()); item.setProductPrice(cp.getContractPrice()); item.setCount(cp.getCount()); return item; yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/quotation/CrmSaleQuotationServiceImpl.java
@@ -20,12 +20,15 @@ import cn.iocoder.yudao.module.crm.dal.mysql.quotation.CrmSaleQuotationMapper; import cn.iocoder.yudao.module.crm.dal.mysql.quotation.CrmSaleQuotationProductMapper; import cn.iocoder.yudao.module.crm.dal.redis.no.CrmNoRedisDAO; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; import cn.iocoder.yudao.module.crm.enums.quotation.CrmSaleQuotationStatusEnum; import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi; import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO; import jakarta.annotation.Resource; @@ -109,7 +112,11 @@ quotationProducts.forEach(p -> p.setQuotationId(saleQuotation.getId())); saleQuotationProductMapper.insertBatch(quotationProducts); // 2.3 创建数据权限 permissionService.createPermission(saleQuotation.getId(), userId); permissionService.createPermission(new CrmPermissionCreateReqBO() .setUserId(userId) .setBizType(CrmBizTypeEnum.CRM_SALE_QUOTATION.getType()) .setBizId(saleQuotation.getId()) .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); return saleQuotation.getId(); } @@ -156,7 +163,7 @@ // 2.2 删除报价明细 saleQuotationProductMapper.deleteByQuotationId(saleQuotation.getId()); // 2.3 删除数据权限 permissionService.deletePermission(saleQuotation.getId()); permissionService.deletePermission(CrmBizTypeEnum.CRM_SALE_QUOTATION.getType(), saleQuotation.getId()); }); } @@ -170,7 +177,7 @@ private List<CrmSaleQuotationProductDO> validateQuotationItems(List<CrmSaleQuotationSaveReqVO.Item> list) { // 1. 校验物料存在且启用 List<Long> itemIds = convertSet(list, CrmSaleQuotationSaveReqVO.Item::getItemId); Set<Long> itemIds = convertSet(list, CrmSaleQuotationSaveReqVO.Item::getItemId); Map<Long, MdmItemRespDTO> itemMap = mdmItemApi.getItemMap(itemIds); // 2. 转换为 CrmSaleQuotationProductDO 列表 return convertList(list, o -> BeanUtils.toBean(o, CrmSaleQuotationProductDO.class, item -> { @@ -223,12 +230,13 @@ private void calculateTotalPrice(CrmSaleQuotationDO saleQuotation, List<CrmSaleQuotationProductDO> items) { saleQuotation.setTotalProductPrice(getSumValue(items, CrmSaleQuotationProductDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)); saleQuotation.setTotalTaxPrice(getSumValue(items, CrmSaleQuotationProductDO::getTaxPrice, BigDecimal::add, BigDecimal.ZERO)); BigDecimal totalTaxPrice = getSumValue(items, CrmSaleQuotationProductDO::getTaxPrice, BigDecimal::add, BigDecimal.ZERO); saleQuotation.setTaxPrice(totalTaxPrice); // 计算优惠价格 if (saleQuotation.getDiscountPercent() == null) { saleQuotation.setDiscountPercent(BigDecimal.ZERO); } BigDecimal basePrice = saleQuotation.getTotalProductPrice().add(saleQuotation.getTotalTaxPrice()); BigDecimal basePrice = saleQuotation.getTotalProductPrice().add(totalTaxPrice); saleQuotation.setDiscountPrice(MoneyUtils.priceMultiplyPercent(basePrice, saleQuotation.getDiscountPercent())); saleQuotation.setTotalPrice(basePrice.subtract(saleQuotation.getDiscountPrice())); }