fix: 报价、审核、采购台账、供应商往来、销售台账、客户往来小数点保留6位小数
已添加1个文件
已修改11个文件
237 ■■■■■ 文件已修改
src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/impl/SupplierServiceImpl.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/common/utils/AmountUtils.java 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordServiceImpl.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/ProcurementBusinessSummaryServiceImpl.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/pojo/SalesQuotationProduct.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesQuotationServiceImpl.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/SalesLedgerProductMapper.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java
@@ -26,6 +26,7 @@
import com.ruoyi.basic.utils.FileUtil;
import com.ruoyi.common.enums.FileNameType;
import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
import com.ruoyi.common.utils.AmountUtils;
import com.ruoyi.common.utils.OrderUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.procurementrecord.utils.StockUtils;
@@ -109,8 +110,8 @@
        approveProcess.setApproveTime(StringUtils.isEmpty(approveProcessVO.getApproveTime()) ? new Date() : dateFormat.parse(approveProcessVO.getApproveTime()));
        approveProcess.setApproveReason(approveProcessVO.getApproveReason());
        approveProcess.setDeviceRepairId(approveProcessVO.getDeviceRepairId());
        approveProcess.setMaintenancePrice(approveProcessVO.getMaintenancePrice());
        approveProcess.setPrice(approveProcessVO.getPrice());
        approveProcess.setMaintenancePrice(AmountUtils.scaleAmount(approveProcessVO.getMaintenancePrice()));
        approveProcess.setPrice(AmountUtils.scaleAmount(approveProcessVO.getPrice()));
        approveProcess.setStartDate(approveProcessVO.getStartDate());
        approveProcess.setEndDate(approveProcessVO.getEndDate());
        approveProcess.setStartDateTime(approveProcessVO.getStartDateTime());
src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java
@@ -16,6 +16,7 @@
import com.ruoyi.basic.pojo.CustomerUser;
import com.ruoyi.basic.service.*;
import com.ruoyi.basic.vo.CustomerVo;
import com.ruoyi.common.utils.AmountUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
@@ -404,6 +405,7 @@
                    unshippedAmount = BigDecimal.ZERO;
                }
                vo.setUnshippedAmount(unshippedAmount);
                AmountUtils.normalizeCustomerTransaction(vo);
            }
        }
        return p;
@@ -431,6 +433,7 @@
                    unshippedAmount = BigDecimal.ZERO;
                }
                vo.setUnshippedAmount(unshippedAmount);
                AmountUtils.normalizeCustomerTransactionDetail(vo);
            }
        }
        return p;
src/main/java/com/ruoyi/basic/service/impl/SupplierServiceImpl.java
@@ -10,6 +10,7 @@
import com.ruoyi.basic.mapper.SupplierManageMapper;
import com.ruoyi.basic.pojo.SupplierManage;
import com.ruoyi.basic.service.ISupplierService;
import com.ruoyi.common.utils.AmountUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
@@ -171,6 +172,7 @@
                vo.setShippedAmount(BigDecimal.ZERO);
                BigDecimal contractAmount = vo.getContractAmounts() == null ? BigDecimal.ZERO : vo.getContractAmounts();
                vo.setUnshippedAmount(contractAmount);
                AmountUtils.normalizeSupplierTransaction(vo);
            }
            return plPage;
        }
@@ -261,6 +263,7 @@
            }
            vo.setShippedAmount(shippedAmount);
            vo.setUnshippedAmount(contractAmount.subtract(shippedAmount));
            AmountUtils.normalizeSupplierTransaction(vo);
        }
        return plPage;
@@ -356,6 +359,7 @@
            }
            vo.setShippedAmount(shippedAmount);
            vo.setUnshippedAmount(contractAmount.subtract(shippedAmount));
            AmountUtils.normalizeSupplierTransactionDetail(vo);
        }
        return plPage;
src/main/java/com/ruoyi/common/utils/AmountUtils.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,124 @@
package com.ruoyi.common.utils;
import com.ruoyi.purchase.dto.ProcurementBusinessSummaryDto;
import com.ruoyi.purchase.vo.SupplierTransactionsDetailsVo;
import com.ruoyi.purchase.vo.SupplierTransactionsVo;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.vo.CustomerTransactionsDetailsVo;
import com.ruoyi.sales.vo.CustomerTransactionsVo;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collection;
import java.util.List;
/**
 * é‡‘额精度工具:统一保留 6 ä½å°æ•°
 */
public final class AmountUtils {
    public static final int AMOUNT_SCALE = 6;
    public static final RoundingMode AMOUNT_ROUNDING = RoundingMode.HALF_UP;
    private AmountUtils() {
    }
    public static BigDecimal scaleAmount(BigDecimal value) {
        if (value == null) {
            return BigDecimal.ZERO.setScale(AMOUNT_SCALE, AMOUNT_ROUNDING);
        }
        return value.setScale(AMOUNT_SCALE, AMOUNT_ROUNDING);
    }
    public static BigDecimal calcTaxExclusiveTotalPrice(BigDecimal taxInclusiveTotalPrice, BigDecimal taxRate) {
        if (taxInclusiveTotalPrice == null || taxRate == null) {
            return scaleAmount(BigDecimal.ZERO);
        }
        BigDecimal divisor = BigDecimal.ONE.add(
                taxRate.divide(BigDecimal.valueOf(100), AMOUNT_SCALE, AMOUNT_ROUNDING)
        );
        return scaleAmount(taxInclusiveTotalPrice.divide(divisor, AMOUNT_SCALE, AMOUNT_ROUNDING));
    }
    public static void normalizeSalesLedgerProduct(SalesLedgerProduct product) {
        if (product == null) {
            return;
        }
        product.setTaxInclusiveUnitPrice(scaleAmount(product.getTaxInclusiveUnitPrice()));
        product.setTaxInclusiveTotalPrice(scaleAmount(product.getTaxInclusiveTotalPrice()));
        product.setTaxExclusiveTotalPrice(scaleAmount(product.getTaxExclusiveTotalPrice()));
    }
    public static void normalizeSalesLedgerProducts(Collection<SalesLedgerProduct> products) {
        if (products == null) {
            return;
        }
        products.forEach(AmountUtils::normalizeSalesLedgerProduct);
    }
    public static void normalizeContractAmount(Object entity) {
        if (entity == null) {
            return;
        }
        try {
            java.lang.reflect.Field field = entity.getClass().getDeclaredField("contractAmount");
            field.setAccessible(true);
            field.set(entity, scaleAmount((BigDecimal) field.get(entity)));
        } catch (NoSuchFieldException ignored) {
        } catch (Exception e) {
            throw new RuntimeException("标准化合同金额失败", e);
        }
    }
    public static void normalizeSupplierTransaction(SupplierTransactionsVo vo) {
        if (vo == null) {
            return;
        }
        vo.setContractAmounts(scaleAmount(vo.getContractAmounts()));
        vo.setShippedAmount(scaleAmount(vo.getShippedAmount()));
        vo.setUnshippedAmount(scaleAmount(vo.getUnshippedAmount()));
    }
    public static void normalizeSupplierTransactionDetail(SupplierTransactionsDetailsVo vo) {
        if (vo == null) {
            return;
        }
        vo.setContractAmount(scaleAmount(vo.getContractAmount()));
        vo.setShippedAmount(scaleAmount(vo.getShippedAmount()));
        vo.setUnshippedAmount(scaleAmount(vo.getUnshippedAmount()));
    }
    public static void normalizeCustomerTransaction(CustomerTransactionsVo vo) {
        if (vo == null) {
            return;
        }
        vo.setContractAmounts(scaleAmount(vo.getContractAmounts()));
        vo.setShippedAmount(scaleAmount(vo.getShippedAmount()));
        vo.setUnshippedAmount(scaleAmount(vo.getUnshippedAmount()));
    }
    public static void normalizeCustomerTransactionDetail(CustomerTransactionsDetailsVo vo) {
        if (vo == null) {
            return;
        }
        vo.setContractAmount(scaleAmount(vo.getContractAmount()));
        vo.setShippedAmount(scaleAmount(vo.getShippedAmount()));
        vo.setUnshippedAmount(scaleAmount(vo.getUnshippedAmount()));
    }
    public static void normalizeProcurementBusinessSummary(ProcurementBusinessSummaryDto dto) {
        if (dto == null) {
            return;
        }
        dto.setPurchaseAmount(scaleAmount(dto.getPurchaseAmount()));
        dto.setAveragePrice(scaleAmount(dto.getAveragePrice()));
        dto.setReturnAmount(scaleAmount(dto.getReturnAmount()));
    }
    public static void normalizeProcurementBusinessSummaryList(List<ProcurementBusinessSummaryDto> list) {
        if (list == null) {
            return;
        }
        list.forEach(AmountUtils::normalizeProcurementBusinessSummary);
    }
}
src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordServiceImpl.java
@@ -7,6 +7,7 @@
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.basic.mapper.ProductModelMapper;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.common.utils.AmountUtils;
import com.ruoyi.common.utils.OrderUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
@@ -708,7 +709,9 @@
            dto.setInboundNum0(dto.getInboundNum().subtract(totalInboundNum));
            // åº“存价值
            if(dto.getTaxInclusiveUnitPrice() != null){
                dto.setTaxInclusiveTotalPrice(dto.getInboundNum0().multiply(dto.getTaxInclusiveUnitPrice()));
                dto.setTaxInclusiveTotalPrice(AmountUtils.scaleAmount(
                        dto.getInboundNum0().multiply(dto.getTaxInclusiveUnitPrice())
                ));
            }
        }
        pageList.setRecords(procurementPageDtoCopyList);
src/main/java/com/ruoyi/purchase/service/impl/ProcurementBusinessSummaryServiceImpl.java
@@ -2,6 +2,7 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.utils.AmountUtils;
import com.ruoyi.purchase.dto.ProcurementBusinessSummaryDto;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import lombok.RequiredArgsConstructor;
@@ -20,6 +21,8 @@
    private final SalesLedgerProductMapper salesLedgerProductMapper;
    public IPage<ProcurementBusinessSummaryDto> listPage(Page page, ProcurementBusinessSummaryDto procurementBusinessSummaryDto) {
        return salesLedgerProductMapper.procurementBusinessSummaryListPage(page, procurementBusinessSummaryDto);
        IPage<ProcurementBusinessSummaryDto> result = salesLedgerProductMapper.procurementBusinessSummaryListPage(page, procurementBusinessSummaryDto);
        AmountUtils.normalizeProcurementBusinessSummaryList(result.getRecords());
        return result;
    }
}
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -20,6 +20,7 @@
import com.ruoyi.basic.utils.FileUtil;
import com.ruoyi.common.enums.FileNameType;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.AmountUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
@@ -61,7 +62,6 @@
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
@@ -122,6 +122,7 @@
        PurchaseLedger purchaseLedger = new PurchaseLedger();
        // DTO转Entity
        BeanUtils.copyProperties(purchaseLedgerDto, purchaseLedger);
        AmountUtils.normalizeContractAmount(purchaseLedger);
        SalesLedger salesLedger = salesLedgerMapper.selectById(purchaseLedgerDto.getSalesLedgerId());
        //录入人
        SysUser sysUser = userMapper.selectUserById(purchaseLedgerDto.getRecorderId());
@@ -235,6 +236,7 @@
        // è®¾ç½®å­—段
        for (SalesLedgerProduct product : products) {
            AmountUtils.normalizeSalesLedgerProduct(product);
            product.setSalesLedgerId(salesLedgerId);
            Long productId = product.getProductId();
@@ -276,10 +278,10 @@
        }
        // è®¡ç®—总含税金额
        BigDecimal totalTaxInclusiveAmount = products.stream()
        BigDecimal totalTaxInclusiveAmount = AmountUtils.scaleAmount(products.stream()
                .map(SalesLedgerProduct::getTaxInclusiveTotalPrice)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
                .reduce(BigDecimal.ZERO, BigDecimal::add));
        // æ›´æ–°ä¸»è¡¨çš„æ€»é‡‘额字段
        if (salesLedgerId != null) {
@@ -377,7 +379,9 @@
        // 4. è½¬æ¢ DTO
        PurchaseLedgerDto resultDto = new PurchaseLedgerDto();
        BeanUtils.copyProperties(purchaseLedger, resultDto);
        AmountUtils.normalizeContractAmount(resultDto);
        if (!products.isEmpty()) {
            AmountUtils.normalizeSalesLedgerProducts(products);
            resultDto.setHasChildren(true);
            resultDto.setProductData(products);
            resultDto.setStorageBlobVOS(fileUtil.getStorageBlobVOsByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum.FILE, RecordTypeEnum.PURCHASE_LEDGER, purchaseLedger.getId()));
@@ -420,6 +424,7 @@
        queryWrapper.eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId())
                .eq(SalesLedgerProduct::getType, 2);
        List<SalesLedgerProduct> productList = salesLedgerProductMapper.selectList(queryWrapper);
        AmountUtils.normalizeSalesLedgerProducts(productList);
        resultDto.setProductData(productList);
        return resultDto;
    }
@@ -451,7 +456,14 @@
    @Override
    public IPage<PurchaseLedgerDto> selectPurchaseLedgerListPage(IPage ipage, PurchaseLedgerDto purchaseLedger) {
        return purchaseLedgerMapper.selectPurchaseLedgerListPage(ipage, purchaseLedger);
        IPage<PurchaseLedgerDto> page = purchaseLedgerMapper.selectPurchaseLedgerListPage(ipage, purchaseLedger);
        if (!CollectionUtils.isEmpty(page.getRecords())) {
            page.getRecords().forEach(record -> {
                AmountUtils.normalizeContractAmount(record);
                AmountUtils.normalizeSalesLedgerProducts(record.getProductData());
            });
        }
        return page;
    }
    @Override
@@ -556,8 +568,14 @@
                    BeanUtils.copyProperties(salesLedgerProductImportDto, salesLedgerProduct);
                    salesLedgerProduct.setSalesLedgerId(salesLedger.getId());
                    salesLedgerProduct.setType(2);
                    AmountUtils.normalizeSalesLedgerProduct(salesLedgerProduct);
                    // è®¡ç®—不含税总价
                    salesLedgerProduct.setTaxExclusiveTotalPrice(salesLedgerProduct.getTaxInclusiveTotalPrice().divide(new BigDecimal(1).add(salesLedgerProduct.getTaxRate().divide(new BigDecimal(100))), 2, RoundingMode.HALF_UP));
                    salesLedgerProduct.setTaxExclusiveTotalPrice(
                            AmountUtils.calcTaxExclusiveTotalPrice(
                                    salesLedgerProduct.getTaxInclusiveTotalPrice(),
                                    salesLedgerProduct.getTaxRate()
                            )
                    );
                    list.stream()
                            .filter(map -> map.get("productName").equals(salesLedgerProduct.getProductCategory()) && map.get("model").equals(salesLedgerProduct.getSpecificationModel()))
                            .findFirst()
@@ -605,7 +623,9 @@
        // 4. è½¬æ¢ DTO
        PurchaseLedgerDto resultDto = new PurchaseLedgerDto();
        BeanUtils.copyProperties(purchaseLedger, resultDto);
        AmountUtils.normalizeContractAmount(resultDto);
        if (!products.isEmpty()) {
            AmountUtils.normalizeSalesLedgerProducts(products);
            resultDto.setHasChildren(true);
            resultDto.setProductData(products);
        }
@@ -623,6 +643,7 @@
        approveProcessVO.setApproveUserIds(purchaseLedger.getApproveUserIds());
        approveProcessVO.setApproveUser(loginUser.getUserId());
        approveProcessVO.setApproveTime(LocalDate.now().toString());
        approveProcessVO.setPrice(AmountUtils.scaleAmount(purchaseLedger.getContractAmount()));
        approveProcessService.addApprove(approveProcessVO);
    }
src/main/java/com/ruoyi/sales/pojo/SalesQuotationProduct.java
@@ -4,6 +4,7 @@
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
@@ -27,11 +28,11 @@
    @Schema(description = "单位")
    private String unit;
    @Schema(description = "单价")
    private Double unitPrice;
    private BigDecimal unitPrice;
    @Schema(description = "数量")
    private Integer quantity;
    @Schema(description = "金额")
    private Double amount;
    private BigDecimal amount;
    @Schema(description = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -4,6 +4,7 @@
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.utils.AmountUtils;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.production.mapper.*;
@@ -89,7 +90,9 @@
    @Override
    public SalesLedgerProduct selectSalesLedgerProductById(Long id) {
        return salesLedgerProductMapper.selectById(id);
        SalesLedgerProduct product = salesLedgerProductMapper.selectById(id);
        AmountUtils.normalizeSalesLedgerProduct(product);
        return product;
    }
    @Override
@@ -97,6 +100,7 @@
        List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectSalesLedgerProductList(salesLedgerProduct);
        if(!CollectionUtils.isEmpty(salesLedgerProducts)){
            salesLedgerProducts.forEach(item -> {
                AmountUtils.normalizeSalesLedgerProduct(item);
                // å‘货信息
                ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>()
                        .eq(ShippingInfo::getSalesLedgerProductId, item.getId())
@@ -164,6 +168,7 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int addOrUpdateSalesLedgerProduct(SalesLedgerProduct salesLedgerProduct) {
        AmountUtils.normalizeSalesLedgerProduct(salesLedgerProduct);
        int result;
        Long salesLedgerId = salesLedgerProduct.getSalesLedgerId();
@@ -280,7 +285,7 @@
            Field amountField = mainEntityClass.getDeclaredField("contractAmount");
            amountField.setAccessible(true);
            amountField.set(entity, totalAmount);
            amountField.set(entity, AmountUtils.scaleAmount(totalAmount));
            mainMapper.updateById(entity);
        } catch (Exception e) {
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -22,6 +22,7 @@
import com.ruoyi.common.enums.FileNameType;
import com.ruoyi.common.enums.SaleEnum;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.AmountUtils;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.EnumUtil;
import com.ruoyi.common.utils.SecurityUtils;
@@ -176,6 +177,7 @@
        productWrapper.eq(SalesLedgerProduct::getSalesLedgerId, salesLedger.getId());
        productWrapper.eq(SalesLedgerProduct::getType, 1);
        List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(productWrapper);
        AmountUtils.normalizeSalesLedgerProducts(products);
        for (SalesLedgerProduct product : products) {
            product.setRegister(SecurityUtils.getLoginUser().getUser().getNickName());
            product.setRegisterDate(LocalDateTime.now());
@@ -202,6 +204,7 @@
        // 4. è½¬æ¢ DTO
        SalesLedgerDto resultDto = new SalesLedgerDto();
        BeanUtils.copyProperties(salesLedger, resultDto);
        AmountUtils.normalizeContractAmount(resultDto);
        if (!products.isEmpty()) {
            resultDto.setHasChildren(true);
            resultDto.setProductData(products);
@@ -317,7 +320,11 @@
    @Override
    public IPage<SalesLedgerVo> selectSalesLedgerListPage(Page page, SalesLedgerDto salesLedgerDto) {
        return salesLedgerMapper.selectSalesLedgerListPage(page, salesLedgerDto);
        IPage<SalesLedgerVo> result = salesLedgerMapper.selectSalesLedgerListPage(page, salesLedgerDto);
        if (!CollectionUtils.isEmpty(result.getRecords())) {
            result.getRecords().forEach(AmountUtils::normalizeContractAmount);
        }
        return result;
    }
    @Override
@@ -394,8 +401,14 @@
                    BeanUtils.copyProperties(salesLedgerProductImportDto, salesLedgerProduct);
                    salesLedgerProduct.setSalesLedgerId(salesLedger.getId());
                    salesLedgerProduct.setType(1);
                    AmountUtils.normalizeSalesLedgerProduct(salesLedgerProduct);
                    // è®¡ç®—不含税总价
                    salesLedgerProduct.setTaxExclusiveTotalPrice(salesLedgerProduct.getTaxInclusiveTotalPrice().divide(new BigDecimal(1).add(salesLedgerProduct.getTaxRate().divide(new BigDecimal(100))), 2, RoundingMode.HALF_UP));
                    salesLedgerProduct.setTaxExclusiveTotalPrice(
                            AmountUtils.calcTaxExclusiveTotalPrice(
                                    salesLedgerProduct.getTaxInclusiveTotalPrice(),
                                    salesLedgerProduct.getTaxRate()
                            )
                    );
                    list.stream()
                            .filter(map -> Objects.equals(map.get("productName"), salesLedgerProduct.getProductCategory()) && Objects.equals(map.get("model"), salesLedgerProduct.getSpecificationModel()))
                            .findFirst()
@@ -558,6 +571,7 @@
        // 2. DTO转Entity
        SalesLedger salesLedger = convertToEntity(salesLedgerDto);
        AmountUtils.normalizeContractAmount(salesLedger);
        salesLedger.setCustomerName(customer.getCustomerName());
        salesLedger.setTenantId(customer.getTenantId());
        // 3. æ–°å¢žæˆ–更新主表
@@ -576,6 +590,7 @@
        // 4. å¤„理子表数据
        List<SalesLedgerProduct> productList = salesLedgerDto.getProductData();
        if (productList != null && !productList.isEmpty()) {
            AmountUtils.normalizeSalesLedgerProducts(productList);
            handleSalesLedgerProducts(salesLedger.getId(), productList, EnumUtil.fromCode(SaleEnum.class, salesLedgerDto.getType()));
            updateMainContractAmount(
                    salesLedger.getId(),
@@ -605,6 +620,7 @@
        // æ‰§è¡Œæ›´æ–°æ“ä½œ
        if (!updateList.isEmpty()) {
            for (SalesLedgerProduct product : updateList) {
                AmountUtils.normalizeSalesLedgerProduct(product);
                product.setType(type.getCode());
                salesLedgerProductMapper.updateById(product);
            }
@@ -612,6 +628,7 @@
        // æ‰§è¡Œæ’入操作
        if (!insertList.isEmpty()) {
            for (SalesLedgerProduct salesLedgerProduct : insertList) {
                AmountUtils.normalizeSalesLedgerProduct(salesLedgerProduct);
                salesLedgerProduct.setType(type.getCode());
                salesLedgerProductMapper.insert(salesLedgerProduct);
                // æ·»åŠ ç”Ÿäº§æ•°æ®
@@ -723,7 +740,7 @@
            Field amountField = mainEntityClass.getDeclaredField("contractAmount");
            amountField.setAccessible(true);
            amountField.set(entity, totalAmount);
            amountField.set(entity, AmountUtils.scaleAmount(totalAmount));
            mainMapper.updateById(entity);
        } catch (Exception e) {
src/main/java/com/ruoyi/sales/service/impl/SalesQuotationServiceImpl.java
@@ -14,6 +14,7 @@
import com.ruoyi.basic.mapper.CustomerMapper;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.common.enums.IsDeleteEnum;
import com.ruoyi.common.utils.AmountUtils;
import com.ruoyi.common.utils.OrderUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
@@ -52,14 +53,33 @@
            return salesQuotationDtoIPage;
        }
        salesQuotationDtoIPage.getRecords().forEach(record -> {
            record.setTotalAmount(AmountUtils.scaleAmount(record.getTotalAmount()));
            List<SalesQuotationProduct> products = salesQuotationProductMapper.selectBySalesQuotationId(record.getId());
            if (!CollectionUtils.isEmpty(products)) {
                products.forEach(product -> {
                    product.setUnitPrice(AmountUtils.scaleAmount(product.getUnitPrice()));
                    product.setAmount(AmountUtils.scaleAmount(product.getAmount()));
                });
            }
            record.setProducts(products);
        });
        return salesQuotationDtoIPage;
    }
    private void normalizeAmounts(SalesQuotationDto salesQuotationDto) {
        salesQuotationDto.setTotalAmount(AmountUtils.scaleAmount(salesQuotationDto.getTotalAmount()));
        if (CollectionUtils.isEmpty(salesQuotationDto.getProducts())) {
            return;
        }
        salesQuotationDto.getProducts().forEach(product -> {
            product.setUnitPrice(AmountUtils.scaleAmount(product.getUnitPrice()));
            product.setAmount(AmountUtils.scaleAmount(product.getAmount()));
        });
    }
    @Override
    public boolean add(SalesQuotationDto salesQuotationDto) {
        normalizeAmounts(salesQuotationDto);
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SalesQuotation salesQuotation = new SalesQuotation();
        BeanUtils.copyProperties(salesQuotationDto, salesQuotation);
@@ -101,6 +121,7 @@
    }
    @Override
    public boolean edit(SalesQuotationDto salesQuotationDto) {
        normalizeAmounts(salesQuotationDto);
        SalesQuotation salesQuotation = new SalesQuotation();
        BeanUtils.copyProperties(salesQuotationDto, salesQuotation);
        ApproveGetAndUpdateVo vo = new ApproveGetAndUpdateVo();
src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
@@ -131,7 +131,7 @@
        SUM(slp.tax_inclusive_total_price) AS purchaseAmount,
        COUNT(DISTINCT slp.sales_ledger_id) AS purchaseTimes,
        <!-- å¹³å‡å•ä»· = æ€»é‡‡è´­é‡‘额/总采购数量,保留2位小数,避免除0 -->
        ROUND(IF(SUM(slp.quantity) = 0, 0, SUM(slp.tax_inclusive_total_price) / SUM(slp.quantity)), 2) AS averagePrice,
        ROUND(IF(SUM(slp.quantity) = 0, 0, SUM(slp.tax_inclusive_total_price) / SUM(slp.quantity)), 6) AS averagePrice,
        <!-- è¯¥äº§å“å¤§ç±»ä¸‹æœ€åŽä¸€ä¸ªå½•入日期(取台账主表的entry_date) -->
        MAX(sl.entry_date) AS entryDate,
        COALESCE(NULLIF(SUM(t1.return_quantity), 0), 0) AS return_quantity,