docs/business_price_field_unification.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,72 @@ # åæº price åæ®µç»ä¸ä¸º businessPrice â å端èè°æ¹æ¡ ## é®é¢èæ¯ å端产åç¼è¾è¡¨ä½¿ç¨ `contractPrice` ä½ä¸ºä»·æ ¼å段åéç»å端ï¼ä½å端使ç¨çæ¯ `businessPrice`ï¼åæºä»·æ ¼ï¼ãä¸¤è æ¯åä¸ä¸ªæ¦å¿µï¼éè¦ç»ä¸ä¸º `businessPrice`ã ## æ¶åé¡µé¢ - åæºæ°å¢/ç¼è¾å¼¹çªï¼`src/views/crm/business/modules/form.vue`ï¼ - 产åç¼è¾è¡¨ç»ä»¶ï¼`src/views/crm/product/components/edit-table.vue`ï¼ - 产åç¼è¾è¡¨åå®ä¹ï¼`src/views/crm/product/components/data.ts`ï¼ ## API 说æ | æ¹æ³ | è·¯å¾ | 说æ | |------|------|------| | PUT | `/crm/business/update` | æ´æ°åæº | | POST | `/crm/business/create` | æ°å¢åæº | **请æ±ä½åæ®µåæ´ï¼`products[]` å ï¼ï¼** | åæ®µ | åæ´ | 说æ | |------|------|------| | `contractPrice` | â ç§»é¤ | æ¹ä¸º `businessPrice` | | `businessPrice` | â ç»ä¸ä½¿ç¨ | åæºä»·æ ¼ | | `totalProductPrice` | â å·²æ | äº§åæ»ä»·ï¼å端已æ°å¢æ¯æï¼ | | `totalPrice` | â å·²æ | åæºæ»ä»·ï¼æåï¼ï¼å端已æ°å¢æ¯æï¼ | ## å端修æ¹ç¹ ### 1. `edit-table.vue` â åæ®µå `contractPrice` â `businessPrice` æä»¶ï¼`src/views/crm/product/components/edit-table.vue` æ¶å 6 å¤ï¼ | è¡å· | ä¿®æ¹ | |------|------| | 55 | `row.contractPrice` â `row.businessPrice` | | 57 | `row.contractPrice` â `row.businessPrice` | | 63 | `row.contractPrice` â `row.businessPrice` | | 70 | `row.contractPrice` â `row.businessPrice` | | 132 | `contractPrice` â `businessPrice`ï¼template slot nameï¼ | | 134 | `row.contractPrice` â `row.businessPrice`ï¼v-modelï¼ | ### 2. `data.ts` â ç¼è¾è¡¨åå®ä¹ æä»¶ï¼`src/views/crm/product/components/data.ts` 第 91-95 è¡ï¼ç¼è¾è¡¨ï¼é business è§å¾ï¼çåå®ä¹ï¼ ``` field: 'contractPrice' â field: 'businessPrice' title: 'ååä»·ï¼å ï¼' â title: 'åæºä»·æ ¼ï¼å ï¼' slots: { default: 'contractPrice' } â slots: { default: 'businessPrice' } ``` ## ä¸å¡è§å说æ | åºæ¯ | è§å | |------|------| | æ´æ°åæºæ¶äº§å `businessPrice` 为 null | å端èªå¨ç¨æ§æ°æ®ç `businessPrice` mergeï¼æ éå端å¤çï¼ | | æ°å¢åæºæ¶ | `businessPrice` å¿ å¡«ï¼ä¸å¯ä¸º null | | 产å `totalPrice` | å端å¯ç´æ¥ä¼ 计ç®å¥½çå¼ï¼å端ä¼å 使ç¨ï¼æªä¼ æ¶åç«¯ç¨ `businessPrice * count` èªå¨è®¡ç® | | 头级 `totalProductPrice` / `totalPrice` | å端å¯ç´æ¥ä¼ ï¼å端ä¸åè¦ç | ## 注æäºé¡¹ - **䏿¶åçæä»¶**ï¼`contract`ã`statistics`ã`report`ã`saleTrace` ä¸ç `contractPrice` æ¯å ¶ä»ä¸å¡æ¦å¿µï¼ä¸ç¨æ¹ - 产å `id` åæ®µå端已æ°å¢æ¯æï¼æ´æ°æ¶ä¼ `id` å³å¯æ è¯å·²æäº§å - å端 `businessPrice` çåå§å弿¥èª `product.salesPrice`ï¼éä¸äº§åæ¶çé»è®¤ä»·ï¼ - æ´æ°æ¶åªéä¼ è¦ä¿®æ¹çåæ®µï¼æªä¼ åæ®µå端èªå¨ä»æ§æ°æ®ç»§æ¿ yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessSaveReqVO.java
@@ -58,6 +58,12 @@ @NotNull(message = "æ´åææ£ä¸è½ä¸ºç©º") private BigDecimal discountPercent; @Schema(description = "äº§åæ»ä»·", example = "12000.00") private BigDecimal totalProductPrice; @Schema(description = "åæºæ»ä»·ï¼æåï¼", example = "11280.00") private BigDecimal totalPrice; @Schema(description = "夿³¨", example = "é便") @DiffLogField(name = "夿³¨") private String remark; @@ -73,6 +79,9 @@ @NoArgsConstructor @AllArgsConstructor public static class BusinessProduct { @Schema(description = "产åå ³èç¼å·", example = "5") private Long id; @Schema(description = "MDM ç©æç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") @NotNull(message = "ç©æç¼å·ä¸è½ä¸ºç©º") @@ -94,6 +103,9 @@ @NotNull(message = "æ°éä¸è½ä¸ºç©º") private BigDecimal count; @Schema(description = "æ»è®¡ä»·æ ¼ï¼businessPrice * countï¼", example = "12000.00") private BigDecimal totalPrice; } } yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java
@@ -134,8 +134,9 @@ updateReqVO.setOwnerUserId(null).setStatusTypeId(null); // ä¸å è®¸æ´æ°çåæ®µ // 1.1 æ ¡éªåå¨ CrmBusinessDO oldBusiness = validateBusinessExists(updateReqVO.getId()); // 1.2 æ ¡éªäº§åé¡¹çæææ§ List<CrmBusinessProductDO> businessProducts = validateBusinessProducts(updateReqVO.getProducts()); // 1.2 æ ¡éªäº§åé¡¹çæææ§ï¼ä¼ å ¥æ§äº§åå表ç¨äºåå¹¶ null åæ®µï¼ List<CrmBusinessProductDO> oldProducts = businessProductMapper.selectListByBusinessId(updateReqVO.getId()); List<CrmBusinessProductDO> businessProducts = validateBusinessProducts(updateReqVO.getProducts(), oldProducts); // 1.3 æ ¡éªå ³èåæ®µ validateRelationDataExists(updateReqVO); @@ -147,7 +148,7 @@ updateBusinessProduct(updateObj.getId(), businessProducts); // 3. è®°å½æä½æ¥å¿ä¸ä¸æ updateReqVO.setOwnerUserId(oldBusiness.getOwnerUserId()); // é¿å æä½æ¥å¿åºç°âå é¤è´è´£äººâçæ åµ updateReqVO.setOwnerUserId(oldBusiness.getOwnerUserId()); // é¿å æä½æ¥å¿åºç°"å é¤è´è´£äºº"çæ åµ LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldBusiness, CrmBusinessSaveReqVO.class)); LogRecordContext.putVariable("businessName", oldBusiness.getName()); } @@ -216,6 +217,18 @@ } private List<CrmBusinessProductDO> validateBusinessProducts(List<CrmBusinessSaveReqVO.BusinessProduct> list) { return validateBusinessProducts(list, Collections.emptyList()); } /** * æ ¡éªäº§åé¡¹çæææ§ï¼æ´æ°åºæ¯åå¹¶æ§æ°æ®ï¼ * * @param list åç«¯ä¼ å ¥ç产åå表 * @param oldProducts å·²æäº§åå表ï¼ç¨äºåå¹¶ null åæ®µï¼ * @return å¤çåç产å DO å表 */ private List<CrmBusinessProductDO> validateBusinessProducts(List<CrmBusinessSaveReqVO.BusinessProduct> list, List<CrmBusinessProductDO> oldProducts) { // 1. æ ¡éªç©æåå¨ Set<Long> itemIds = convertSet(list, CrmBusinessSaveReqVO.BusinessProduct::getItemId); Map<Long, MdmItemRespDTO> itemMap = mdmItemApi.getItemMap(itemIds); @@ -224,16 +237,48 @@ throw exception(PRODUCT_NOT_EXISTS); } } // 2. 转å为 CrmBusinessProductDO å表 return convertList(list, o -> BeanUtils.toBean(o, CrmBusinessProductDO.class, item -> item.setTotalPrice(MoneyUtils.priceMultiply(item.getBusinessPrice(), item.getCount())))); // 2. æå»ºæ§äº§å Mapï¼æ id ç´¢å¼ï¼ Map<Long, CrmBusinessProductDO> oldProductMap = convertMap(oldProducts, CrmBusinessProductDO::getId); // 3. 转å为 CrmBusinessProductDO å表ï¼åå¹¶æ§æ°æ®ï¼ return convertList(list, o -> { CrmBusinessProductDO product = BeanUtils.toBean(o, CrmBusinessProductDO.class); // æ´æ°åºæ¯ï¼å¦æäº§åå·²æ id ä¸ææ§æ°æ®ï¼ååå¹¶ null åæ®µ if (o.getId() != null && oldProductMap.containsKey(o.getId())) { CrmBusinessProductDO old = oldProductMap.get(o.getId()); if (product.getBusinessPrice() == null) { product.setBusinessPrice(old.getBusinessPrice()); } if (product.getItemPrice() == null) { product.setItemPrice(old.getItemPrice()); } if (product.getCount() == null) { product.setCount(old.getCount()); } if (product.getItemUnitId() == null) { product.setItemUnitId(old.getItemUnitId()); } } // ä¼å 使ç¨åç«¯ä¼ å ¥ç totalPriceï¼å¦åéè¿ businessPrice * count è®¡ç® if (o.getTotalPrice() != null) { product.setTotalPrice(o.getTotalPrice()); } else { product.setTotalPrice(MoneyUtils.priceMultiply(product.getBusinessPrice(), product.getCount())); } return product; }); } private void calculateTotalPrice(CrmBusinessDO business, List<CrmBusinessProductDO> businessProducts) { // totalProductPriceï¼ä¼å 使ç¨åç«¯ä¼ å ¥å¼ï¼å¦åä»äº§åæ±æ» if (business.getTotalProductPrice() == null) { business.setTotalProductPrice(getSumValue(businessProducts, CrmBusinessProductDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)); } // totalPriceï¼ä¼å 使ç¨åç«¯ä¼ å ¥å¼ï¼å¦åæææ£è®¡ç® if (business.getTotalPrice() == null) { BigDecimal discountPrice = MoneyUtils.priceMultiplyPercent(business.getTotalProductPrice(), business.getDiscountPercent()); business.setTotalPrice(business.getTotalProductPrice().subtract(discountPrice)); } } @Override @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_UPDATE_STATUS_SUB_TYPE, bizNo = "{{#reqVO.id}}",