yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpSaleStatisticsServiceImpl.java
@@ -1,11 +1,24 @@
package cn.iocoder.yudao.module.erp.service.statistics;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.crm.api.customer.CrmCustomerApi;
import cn.iocoder.yudao.module.crm.api.customer.dto.CrmCustomerRespDTO;
import cn.iocoder.yudao.module.erp.controller.admin.statistics.vo.sale.ErpSaleCustomerSummaryRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.statistics.vo.sale.ErpSaleProductSummaryRespVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleCustomerReceiptStatisticsDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleCustomerStatisticsDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleProductStatisticsDO;
import cn.iocoder.yudao.module.erp.dal.mysql.statistics.ErpSaleStatisticsMapper;
import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi;
import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
 * ERP 销售统计 Service 实现类
@@ -18,9 +31,78 @@
    @Resource
    private ErpSaleStatisticsMapper saleStatisticsMapper;
    @Resource
    private CrmCustomerApi customerApi;
    @Resource
    private MdmItemApi mdmItemApi;
    @Override
    public BigDecimal getSalePrice(LocalDateTime beginTime, LocalDateTime endTime) {
        return saleStatisticsMapper.getSalePrice(beginTime, endTime);
    }
    @Override
    public List<ErpSaleCustomerSummaryRespVO> getCustomerSummary(Long customerId, LocalDateTime beginTime, LocalDateTime endTime) {
        List<ErpSaleCustomerStatisticsDO> saleList = saleStatisticsMapper.selectCustomerStatistics(customerId, beginTime, endTime);
        if (CollectionUtils.isAnyEmpty(saleList)) {
            return new ArrayList<>();
        }
        // 1. 已收款金额按客户归集(收款单可能早于/晚于订单,不做订单级勾稽,只按客户汇总)
        Map<Long, BigDecimal> receiptMap = CollectionUtils.convertMap(
                saleStatisticsMapper.selectCustomerReceiptStatistics(customerId, beginTime, endTime),
                ErpSaleCustomerReceiptStatisticsDO::getCustomerId,
                ErpSaleCustomerReceiptStatisticsDO::getReceiptAmount);
        // 2. 客户名称
        Map<Long, CrmCustomerRespDTO> customerMap = customerApi.getCustomerMap(
                CollectionUtils.convertSet(saleList, ErpSaleCustomerStatisticsDO::getCustomerId));
        // 3. 组装
        List<ErpSaleCustomerSummaryRespVO> result = new ArrayList<>(saleList.size());
        for (ErpSaleCustomerStatisticsDO sale : saleList) {
            BigDecimal saleAmount = sale.getSaleAmount() == null ? BigDecimal.ZERO : sale.getSaleAmount();
            BigDecimal receiptAmount = receiptMap.getOrDefault(sale.getCustomerId(), BigDecimal.ZERO);
            CrmCustomerRespDTO customer = customerMap.get(sale.getCustomerId());
            ErpSaleCustomerSummaryRespVO vo = new ErpSaleCustomerSummaryRespVO();
            vo.setCustomerId(sale.getCustomerId());
            vo.setCustomerName(customer != null ? customer.getName() : "客户(" + sale.getCustomerId() + ")");
            vo.setOrderCount(sale.getOrderCount());
            vo.setSaleAmount(saleAmount);
            vo.setReceiptAmount(receiptAmount);
            vo.setUnreceivedAmount(saleAmount.subtract(receiptAmount));
            vo.setLastOrderTime(sale.getLastOrderTime());
            result.add(vo);
        }
        return result;
    }
    @Override
    public List<ErpSaleProductSummaryRespVO> getProductSummary(Long productId, LocalDateTime beginTime, LocalDateTime endTime) {
        List<ErpSaleProductStatisticsDO> saleList = saleStatisticsMapper.selectProductStatistics(productId, beginTime, endTime);
        if (CollectionUtils.isAnyEmpty(saleList)) {
            return new ArrayList<>();
        }
        // 1. 产品名称与参考成本价
        Map<Long, MdmItemRespDTO> itemMap = mdmItemApi.getItemMap(
                CollectionUtils.convertSet(saleList, ErpSaleProductStatisticsDO::getProductId));
        // 2. 组装,毛利 = 销售金额 - 数量 × 参考成本价
        List<ErpSaleProductSummaryRespVO> result = new ArrayList<>(saleList.size());
        for (ErpSaleProductStatisticsDO sale : saleList) {
            MdmItemRespDTO item = itemMap.get(sale.getProductId());
            BigDecimal saleAmount = sale.getSaleAmount() == null ? BigDecimal.ZERO : sale.getSaleAmount();
            BigDecimal costPrice = item != null && item.getCostPrice() != null ? item.getCostPrice() : BigDecimal.ZERO;
            BigDecimal totalCount = sale.getTotalCount() == null ? BigDecimal.ZERO : sale.getTotalCount();
            BigDecimal costAmount = costPrice.multiply(totalCount);
            ErpSaleProductSummaryRespVO vo = new ErpSaleProductSummaryRespVO();
            vo.setProductId(sale.getProductId());
            vo.setProductName(item != null ? item.getName() : "产品(" + sale.getProductId() + ")");
            vo.setOrderCount(sale.getOrderCount());
            vo.setTotalCount(totalCount);
            vo.setSaleAmount(saleAmount);
            vo.setCostAmount(costAmount);
            vo.setProfitAmount(saleAmount.subtract(costAmount));
            result.add(vo);
        }
        return result;
    }
}