| src/main/java/com/ruoyi/common/utils/BigDecimalUtils.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/ruoyi/production/controller/ProductBomController.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/ruoyi/production/dto/ProductBomDto.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/ruoyi/production/service/ProductBomService.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/ruoyi/production/service/impl/ProductBomServiceImpl.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/main/java/com/ruoyi/common/utils/BigDecimalUtils.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,180 @@ package com.ruoyi.common.utils; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.Arrays; import java.util.Collection; import java.util.Optional; /** * @author yuan * @date 2026-04-23 13:10 * @description BigDecimalå·¥å ·ç±» */ public class BigDecimalUtils { public static BigDecimal getBigDecimalValue(BigDecimal val) { return Optional.ofNullable(val).orElse(BigDecimal.ZERO); } public static BigDecimal of(Object val) { if (val == null) { return null; } try { if (val instanceof Double || val instanceof Float) { return BigDecimal.valueOf(((Number) val).doubleValue()); } if (val instanceof Number) { return new BigDecimal(val.toString()); } return new BigDecimal(val.toString().trim()); } catch (NumberFormatException e) { throw new IllegalArgumentException("æ æ³è½¬æ¢ " + val + " 为 BigDecimalç±»å ", e); } } /** * å®å ¨è½¬æ¢æ¹æ³ï¼å°å¯¹è±¡è½¬ä¸ºBigDecimalï¼nullè§ä¸º0 * @param number å¯ä»¥æ¯NumberãStringæBigDecimal * @return 对åºçBigDecimalï¼null转为0 */ public static BigDecimal safe(Object number) { if (number == null) return BigDecimal.ZERO; if (number instanceof BigDecimal) return (BigDecimal) number; if (number instanceof Number) return BigDecimal.valueOf(((Number) number).doubleValue()); try { return new BigDecimal(number.toString()); } catch (NumberFormatException e) { return BigDecimal.ZERO; } } /** * å æ³è¿ç®ï¼èªå¨å¤çnullå¼ï¼ * @param values å¤ä¸ªå æ° * @return å */ public static BigDecimal add(Object... values) { return Arrays.stream(values) .map(BigDecimalUtils::safe) .reduce(BigDecimal.ZERO, BigDecimal::add); } /** * åæ³è¿ç®ï¼èªå¨å¤çnullå¼ï¼ * @param minuend è¢«åæ° * @param subtrahends åæ° * @return å·® */ public static BigDecimal subtract(Object minuend, Object... subtrahends) { BigDecimal result = safe(minuend); for (Object subtrahend : subtrahends) { result = result.subtract(safe(subtrahend)); } return result; } /** * 乿³è¿ç®ï¼èªå¨å¤çnullå¼ï¼ä»»ä½åæ°ä¸ºnullåè¿å0ï¼ * @param values å¤ä¸ªä¹æ° * @return 积 */ public static BigDecimal multiply(Object... values) { if (values == null || values.length == 0) { return BigDecimal.ZERO; } BigDecimal result = Arrays.stream(values) .map(BigDecimalUtils::safe) .reduce(BigDecimal.ONE, BigDecimal::multiply); // æ ååç»æï¼å¦ææ¯0ï¼å»é¤ææå°æ°ä½ï¼å¦åä¿çåæå°æ°ä½ return stripTrailingZeros(result); } /** * 餿³è¿ç®ï¼èªå¨å¤çnullå¼ï¼ * @param dividend è¢«é¤æ° * @param divisor 餿° * @param scale å°æ°ä½æ° * @param roundingMode èå ¥æ¨¡å¼ * @return å */ public static BigDecimal divide(Object dividend, Object divisor, int scale, RoundingMode roundingMode) { BigDecimal d1 = safe(dividend); BigDecimal d2 = safe(divisor); if (d2.compareTo(BigDecimal.ZERO) == 0) { return BigDecimal.ZERO; } return stripTrailingZeros(d1.divide(d2, scale, roundingMode)); } /** * 餿³è¿ç®ï¼èªå¨å¤çnullå¼ï¼ * @param dividend è¢«é¤æ° * @param divisor 餿° * @param scale å°æ°ä½æ° * @param roundingMode èå ¥æ¨¡å¼ * @return å */ public static BigDecimal dividePercentage(Object dividend, Object divisor, int scale, RoundingMode roundingMode) { BigDecimal d1 = safe(dividend); BigDecimal d2 = safe(divisor); if (d2.compareTo(BigDecimal.ZERO) == 0) { return BigDecimal.ZERO; } BigDecimal multiplied = d1.multiply(new BigDecimal("100")); BigDecimal result = multiplied.divide(d2, scale, roundingMode); return stripTrailingZeros(result); } /** * æ¯è¾ä¸¤ä¸ªæ°ç大å°ï¼èªå¨å¤çnullå¼ï¼nullè§ä¸º0ï¼ * @param num1 第ä¸ä¸ªæ° * @param num2 第äºä¸ªæ° * @return 1: num1 > num2; 0: num1 = num2; -1: num1 < num2 */ public static int compare(Object num1, Object num2) { return safe(num1).compareTo(safe(num2)); } /** * åèäºå ¥ï¼èªå¨å¤çnullå¼ï¼ * @param value åå§å¼ * @param scale ä¿çå°æ°ä½æ° * @return åèäºå ¥åçå¼ */ public static BigDecimal round(Object value, int scale) { return safe(value).setScale(scale, RoundingMode.HALF_UP); } /** * æ±åï¼æµå¼å¤ççï¼ * @param numbers æ°åéå * @return å */ public static BigDecimal sum(Collection<?> numbers) { return numbers.stream() .map(BigDecimalUtils::safe) .reduce(BigDecimal.ZERO, BigDecimal::add); } /** * æ ååBigDecimalç»æ * 1. 妿æ¯0ï¼å»é¤ææå°æ°ä½ * 2. 妿䏿¯0ï¼å»é¤æ«å°¾æ æä¹ç0 */ public static BigDecimal stripTrailingZeros(BigDecimal value) { if (value.compareTo(BigDecimal.ZERO) == 0) { return BigDecimal.ZERO; } return new BigDecimal(value.stripTrailingZeros().toPlainString()); } } src/main/java/com/ruoyi/production/controller/ProductBomController.java
@@ -69,6 +69,13 @@ return productBomService.add(productBom); } @ApiModelProperty("å¤å¶BOM") @PostMapping("/copy") @Log(title = "å¤å¶BOM", businessType = BusinessType.INSERT) public AjaxResult copy(@RequestBody ProductBomDto productBom) { return productBomService.copy(productBom); } @ApiOperation("æ´æ°BOM") @Log(title = "ä¿®æ¹", businessType = BusinessType.UPDATE) @PutMapping("/update") src/main/java/com/ruoyi/production/dto/ProductBomDto.java
@@ -17,4 +17,7 @@ //ç©æç¼ç private String materialCode; //ç©æç¼ç private Long copyId; } src/main/java/com/ruoyi/production/service/ProductBomService.java
@@ -29,4 +29,6 @@ void exportBom(HttpServletResponse response, Integer bomId); AjaxResult update(ProductBom productBom); AjaxResult copy(ProductBomDto productBom); } src/main/java/com/ruoyi/production/service/impl/ProductBomServiceImpl.java
@@ -2,6 +2,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.basic.pojo.Product; @@ -20,6 +21,7 @@ import com.ruoyi.production.service.ProductBomService; import com.ruoyi.production.service.ProductProcessService; import com.ruoyi.production.service.ProductStructureService; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -188,6 +190,115 @@ @Override @Transactional(rollbackFor = Exception.class) public AjaxResult copy(ProductBomDto productBom) { Long copyId = productBom.getCopyId(); if (copyId == null) { throw new ServiceException("å¤å¶æºBOM IDä¸è½ä¸ºç©º"); } ProductBom sourceBom = productBomMapper.selectById(copyId); if (sourceBom == null) { throw new ServiceException("å¤å¶æºBOMä¸åå¨"); } ProductBom newBom = getProductBom(productBom, sourceBom); productBomMapper.insert(newBom); newBom.setBomNo("BM." + String.format("%05d", newBom.getId())); productBomMapper.updateById(newBom); ProductModel productModel = productModelService.getById(newBom.getProductModelId()); if (productModel == null) { throw new ServiceException("éæ©çäº§åæ¨¡åä¸åå¨"); } ProductStructure newRoot = getProductStructure(newBom, productModel); productStructureService.save(newRoot); List<ProductStructure> sourceStructures = productStructureMapper.selectList( Wrappers.<ProductStructure>lambdaQuery() .eq(ProductStructure::getBomId, copyId.intValue())); if (sourceStructures == null || sourceStructures.isEmpty()) { return AjaxResult.success(); } ProductStructure oldRoot = sourceStructures.stream() .filter(s -> s.getParentId() == null) .findFirst().orElse(new ProductStructure()); List<ProductStructure> children = sourceStructures .stream() .filter(s -> !s.getId().equals(oldRoot.getId())) .collect(Collectors.toList()); Map<Long, Long> oldNewIdMap = new HashMap<>(); oldNewIdMap.put(oldRoot.getId(), newRoot.getId()); List<ProductStructure> insertList = children .stream() .map(item -> getProductStructures(item, newBom)) .collect(Collectors.toList()); productStructureService.saveBatch(insertList); for (int i = 0; i < children.size(); i++) { oldNewIdMap.put( children.get(i).getId(), insertList.get(i).getId() ); } List<ProductStructure> updateList = new ArrayList<>(); for (int i = 0; i < children.size(); i++) { ProductStructure source = children.get(i); ProductStructure inserted = insertList.get(i); Long newParentId = oldNewIdMap.get(source.getParentId()); if (newParentId != null) { inserted.setParentId(newParentId); updateList.add(inserted); } } if (!updateList.isEmpty()) { productStructureService.updateBatchById(updateList); } return AjaxResult.success(); } @NotNull private static ProductStructure getProductStructures(ProductStructure item, ProductBom newBom) { ProductStructure copy = new ProductStructure(); copy.setProductModelId(item.getProductModelId()); copy.setProcessId(item.getProcessId()); copy.setUnitQuantity(item.getUnitQuantity()); copy.setDemandedQuantity(item.getDemandedQuantity()); copy.setUnit(item.getUnit()); copy.setBomId(newBom.getId()); return copy; } @NotNull private static ProductStructure getProductStructure(ProductBom newBom, ProductModel productModel) { ProductStructure newRoot = new ProductStructure(); newRoot.setProductModelId(newBom.getProductModelId()); newRoot.setUnitQuantity(BigDecimal.valueOf(1)); newRoot.setUnit(productModel.getUnit()); newRoot.setBomId(newBom.getId()); return newRoot; } @NotNull private static ProductBom getProductBom(ProductBomDto productBom, ProductBom sourceBom) { ProductBom newBom = new ProductBom(); newBom.setProductModelId(productBom.getProductModelId() != null ? productBom.getProductModelId() : sourceBom.getProductModelId()); newBom.setRemark(productBom.getRemark()); newBom.setVersion(productBom.getVersion() != null ? productBom.getVersion() : sourceBom.getVersion()); return newBom; } @Override @Transactional(rollbackFor = Exception.class) public AjaxResult uploadBom(MultipartFile file) { ExcelUtil<BomImportDto> util = new ExcelUtil<>(BomImportDto.class); List<BomImportDto> list;