Просмотр исходного кода

友盛-统计报表-销售报表

tangyishan 1 месяц назад
Родитель
Сommit
6c4a07d4fc
24 измененных файлов с 912 добавлено и 0 удалено
  1. 3 0
      sckw-common/sckw-common-core/src/main/java/com/sckw/core/web/response/BaseResult.java
  2. 39 0
      sckw-modules-api/sckw-contract-api/src/main/java/com/sckw/contract/api/feign/SalesReportContractFeignService.java
  3. 14 0
      sckw-modules-api/sckw-contract-api/src/main/java/com/sckw/contract/api/model/dto/req/SalesReportGoodsQueryDto.java
  4. 23 0
      sckw-modules-api/sckw-contract-api/src/main/java/com/sckw/contract/api/model/dto/res/SalesReportGoodsResVo.java
  5. 26 0
      sckw-modules-api/sckw-order-api/src/main/java/com/sckw/order/api/feign/SalesReportOrderFeignService.java
  6. 61 0
      sckw-modules-api/sckw-order-api/src/main/java/com/sckw/order/api/model/SalesReportDataVo.java
  7. 36 0
      sckw-modules-api/sckw-order-api/src/main/java/com/sckw/order/api/model/SalesReportQueryDto.java
  8. 14 0
      sckw-modules/sckw-contract/src/main/java/com/sckw/contract/controller/KwcPurchaseController.java
  9. 1 0
      sckw-modules/sckw-contract/src/main/java/com/sckw/contract/dubbo/RemoteContractServiceImpl.java
  10. 2 0
      sckw-modules/sckw-contract/src/main/java/com/sckw/contract/service/operateService/KwcContractLogisticsService.java
  11. 73 0
      sckw-modules/sckw-contract/src/main/java/com/sckw/contract/service/operateService/KwcContractTradeService.java
  12. 15 0
      sckw-modules/sckw-order/src/main/java/com/sckw/order/controller/KwoTradeOrderStatisticsController.java
  13. 12 0
      sckw-modules/sckw-order/src/main/java/com/sckw/order/dao/KwoTradeOrderMapper.java
  14. 18 0
      sckw-modules/sckw-order/src/main/java/com/sckw/order/model/SalesReportRawData.java
  15. 99 0
      sckw-modules/sckw-order/src/main/java/com/sckw/order/serivce/KwoTradeOrderStatisticsService.java
  16. 21 0
      sckw-modules/sckw-order/src/main/resources/mapper/KwoTradeOrderMapper.xml
  17. 77 0
      sckw-modules/sckw-report/src/main/java/com/sckw/report/controller/KwSalesReportController.java
  18. 36 0
      sckw-modules/sckw-report/src/main/java/com/sckw/report/model/dto/SalesReportDTO.java
  19. 18 0
      sckw-modules/sckw-report/src/main/java/com/sckw/report/model/vo/CustomerVO.java
  20. 18 0
      sckw-modules/sckw-report/src/main/java/com/sckw/report/model/vo/ProductVO.java
  21. 35 0
      sckw-modules/sckw-report/src/main/java/com/sckw/report/model/vo/SalesReportSummaryVO.java
  22. 77 0
      sckw-modules/sckw-report/src/main/java/com/sckw/report/model/vo/SalesReportVO.java
  23. 46 0
      sckw-modules/sckw-report/src/main/java/com/sckw/report/service/KwSalesReportService.java
  24. 148 0
      sckw-modules/sckw-report/src/main/java/com/sckw/report/service/impl/KwSalesReportServiceImpl.java

+ 3 - 0
sckw-common/sckw-common-core/src/main/java/com/sckw/core/web/response/BaseResult.java

@@ -58,4 +58,7 @@ public class BaseResult<T> implements Serializable {
     }
 
 
+    public boolean isSuccess() {
+        return code == HttpStatus.SUCCESS_CODE;
+    }
 }

+ 39 - 0
sckw-modules-api/sckw-contract-api/src/main/java/com/sckw/contract/api/feign/SalesReportContractFeignService.java

@@ -0,0 +1,39 @@
+package com.sckw.contract.api.feign;
+
+import com.sckw.contract.api.model.dto.req.SalesReportGoodsQueryDto;
+import com.sckw.contract.api.model.dto.req.TradeEntListQueryFeignDto;
+import com.sckw.contract.api.model.dto.res.SalesReportGoodsResVo;
+import com.sckw.contract.api.model.dto.res.TradeEntInfoResVo;
+import com.sckw.core.web.response.BaseResult;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import java.util.List;
+
+/**
+ * 销售报表相关Feign接口
+ */
+@FeignClient(name = "sckw-ng-contract", contextId = "salesReportFeignService")
+public interface SalesReportContractFeignService {
+
+    /**
+     * 查询销售报表客户列表
+     * 范围为与当前公司存在合同(含已结束)的所有贸易商
+     *
+     * @param queryFeignDto 查询参数
+     * @return 客户列表
+     */
+    @PostMapping("/kwcPurchase/queryTradeEntList")
+    BaseResult<List<TradeEntInfoResVo>> queryTradeEntList(@RequestBody TradeEntListQueryFeignDto queryFeignDto);
+
+    /**
+     * 查询销售报表商品列表
+     * 范围为与当前公司存在合同(含已结束)的所有商品
+     *
+     * @param queryDto 查询参数
+     * @return 商品列表
+     */
+    @PostMapping("/kwcPurchase/goodsList")
+    BaseResult<List<SalesReportGoodsResVo>> queryGoodsList(@RequestBody SalesReportGoodsQueryDto queryDto);
+}

+ 14 - 0
sckw-modules-api/sckw-contract-api/src/main/java/com/sckw/contract/api/model/dto/req/SalesReportGoodsQueryDto.java

@@ -0,0 +1,14 @@
+package com.sckw.contract.api.model.dto.req;
+
+import lombok.Data;
+
+/**
+ * 销售报表商品列表查询参数
+ */
+@Data
+public class SalesReportGoodsQueryDto {
+    /**
+     * 当前企业的 id
+     */
+    private Long curEntId;
+}

+ 23 - 0
sckw-modules-api/sckw-contract-api/src/main/java/com/sckw/contract/api/model/dto/res/SalesReportGoodsResVo.java

@@ -0,0 +1,23 @@
+package com.sckw.contract.api.model.dto.res;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 销售报表商品信息
+ */
+@Data
+public class SalesReportGoodsResVo implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 商品id
+     */
+    private Long goodsId;
+
+    /**
+     * 商品名称
+     */
+    private String goodsName;
+}

+ 26 - 0
sckw-modules-api/sckw-order-api/src/main/java/com/sckw/order/api/feign/SalesReportOrderFeignService.java

@@ -0,0 +1,26 @@
+package com.sckw.order.api.feign;
+
+import com.sckw.core.web.response.BaseResult;
+import com.sckw.order.api.model.SalesReportDataVo;
+import com.sckw.order.api.model.SalesReportQueryDto;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import java.util.List;
+
+/**
+ * 销售报表相关Feign接口
+ */
+@FeignClient(name = "sckw-ng-order", contextId = "salesReportFeignService")
+public interface SalesReportOrderFeignService {
+
+    /**
+     * 查询销售报表数据
+     *
+     * @param queryDto 查询参数
+     * @return 销售报表数据列表
+     */
+    @PostMapping("/kwoTradeOrderStatistics/querySalesReportData")
+    BaseResult<List<SalesReportDataVo>> querySalesReportData(@RequestBody SalesReportQueryDto queryDto);
+}

+ 61 - 0
sckw-modules-api/sckw-order-api/src/main/java/com/sckw/order/api/model/SalesReportDataVo.java

@@ -0,0 +1,61 @@
+package com.sckw.order.api.model;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 销售报表数据响应
+ */
+@Data
+public class SalesReportDataVo implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Long customerId;
+
+    /**
+     * 客户名称
+     */
+    private String customerName;
+
+    /**
+     * 商品ID
+     */
+    private Long goodsId;
+
+    /**
+     * 商品名称
+     */
+    private String goodsName;
+
+    /**
+     * 销售数量(吨)
+     */
+    private BigDecimal salesQuantity;
+
+    /**
+     * 销售平均单价(元/吨)
+     */
+    private BigDecimal averagePrice;
+
+    /**
+     * 销售额(元)
+     */
+    private BigDecimal salesAmount;
+
+    /**
+     * 累计销售数量(吨)
+     */
+    private BigDecimal cumulativeQuantity;
+
+    /**
+     * 累计平均销售单价(元/吨)
+     */
+    private BigDecimal cumulativeAveragePrice;
+
+    /**
+     * 累计销售额(元)
+     */
+    private BigDecimal cumulativeAmount;
+}

+ 36 - 0
sckw-modules-api/sckw-order-api/src/main/java/com/sckw/order/api/model/SalesReportQueryDto.java

@@ -0,0 +1,36 @@
+package com.sckw.order.api.model;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 销售报表查询参数
+ */
+@Data
+public class SalesReportQueryDto {
+    /**
+     * 当前企业的 id
+     */
+    private Long curEntId;
+
+    /**
+     * 客户企业id
+     */
+    private Long customerId;
+
+    /**
+     * 商品id
+     */
+    private Long goodsId;
+
+    /**
+     * 开始时间(yyyy-MM-dd)
+     */
+    private String startTime;
+
+    /**
+     * 结束时间(yyyy-MM-dd)
+     */
+    private String endTime;
+}

+ 14 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/controller/KwcPurchaseController.java

@@ -1,6 +1,8 @@
 package com.sckw.contract.controller;
 
+import com.sckw.contract.api.model.dto.req.SalesReportGoodsQueryDto;
 import com.sckw.contract.api.model.dto.req.TradeEntListQueryFeignDto;
+import com.sckw.contract.api.model.dto.res.SalesReportGoodsResVo;
 import com.sckw.contract.model.vo.req.IdReqVo;
 import com.sckw.contract.model.vo.req.QueryListReqVo;
 import com.sckw.contract.api.model.dto.res.TradeEntInfoResVo;
@@ -49,6 +51,18 @@ public class KwcPurchaseController {
         return BaseResult.success(kwcContractTradeService.queryTradeEntList(queryFeignDto));
     }
 
+    /**
+     * 查询销售报表商品列表
+     * 范围为与当前公司存在合同(含已结束)的所有商品
+     *
+     * @param queryDto 查询参数
+     * @return 商品列表
+     */
+    @PostMapping("/goodsList")
+    public BaseResult<List<SalesReportGoodsResVo>> queryGoodsList(@RequestBody SalesReportGoodsQueryDto queryDto) {
+        return BaseResult.success(kwcContractTradeService.querySalesReportGoodsList(queryDto));
+    }
+
     /**
      * @desc: 合同详情
      * @param reqVo id

+ 1 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/dubbo/RemoteContractServiceImpl.java

@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.google.common.collect.Sets;
 import com.sckw.contract.api.RemoteContractService;
 import com.sckw.contract.api.model.dto.req.ContractAuditPara;
+import com.sckw.contract.api.model.dto.req.TradeEntListQueryFeignDto;
 import com.sckw.contract.api.model.dto.res.*;
 import com.sckw.contract.api.model.vo.*;
 import com.sckw.contract.dao.*;

+ 2 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/service/operateService/KwcContractLogisticsService.java

@@ -12,9 +12,11 @@ import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import com.sckw.contract.api.model.dto.req.TradeEntListQueryFeignDto;
 import com.sckw.contract.api.model.dto.res.TradeEntInfoResVo;
+import com.sckw.contract.api.model.dto.req.TradeEntListQueryFeignDto;
 import com.sckw.contract.dao.KwcContractLogisticsMapper;
 import com.sckw.contract.model.dto.req.QueryListReqDto;
 import com.sckw.contract.model.dto.res.QueryListResDto;
+import com.sckw.contract.api.model.dto.res.TradeEntInfoResVo;
 import com.sckw.contract.model.entity.*;
 import com.sckw.contract.model.report.LogisticsListExport;
 import com.sckw.contract.model.vo.req.*;

+ 73 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/service/operateService/KwcContractTradeService.java

@@ -9,6 +9,7 @@ import com.github.pagehelper.PageInfo;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+import com.sckw.contract.api.model.dto.req.SalesReportGoodsQueryDto;
 import com.sckw.contract.api.model.dto.req.TradeEntListQueryFeignDto;
 import com.sckw.contract.api.model.dto.res.*;
 import com.sckw.contract.api.model.vo.LogisticsEntDtoVO;
@@ -17,6 +18,7 @@ import com.sckw.contract.api.model.vo.TradeContractUnitDto;
 import com.sckw.contract.dao.KwcContractTradeMapper;
 import com.sckw.contract.model.dto.req.QueryListReqDto;
 import com.sckw.contract.model.dto.res.QueryListResDto;
+import com.sckw.contract.api.model.dto.res.TradeEntInfoResVo;
 import com.sckw.contract.model.entity.*;
 import com.sckw.contract.model.report.TradeListExport;
 import com.sckw.contract.model.vo.req.*;
@@ -1951,6 +1953,77 @@ public class KwcContractTradeService {
         return resVos;
     }
 
+    /**
+     * 查询销售报表商品列表
+     * 范围为与当前公司存在合同(含已结束)的所有商品
+     *
+     * @param queryDto 查询参数
+     * @return 商品列表
+     */
+    public List<SalesReportGoodsResVo> querySalesReportGoodsList(SalesReportGoodsQueryDto queryDto) {
+        List<SalesReportGoodsResVo> resVos = new ArrayList<>();
+        Long entId = queryDto.getCurEntId();
+
+        Set<Long> entIds = Sets.newHashSet();
+        entIds.add(entId);
+
+        Set<Long> contractIds = null;
+        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(entIds)) {
+            List<KwcContractTradeUnit> units = kwcContractTradeUnitRepository.queryByEntIds(entIds);
+            if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(units)) {
+                contractIds = units.stream()
+                        .map(KwcContractTradeUnit::getContractId)
+                        .collect(Collectors.toSet());
+            }
+        }
+
+        if (org.apache.commons.collections4.CollectionUtils.isEmpty(contractIds)) {
+            return Collections.emptyList();
+        }
+
+        List<KwcContractTradeGoods> tradeGoods = kwcContractTradeGoodsRepository.queryByContractIds(contractIds);
+
+        // 提取所有商品ID
+        Set<Long> goodsIds = tradeGoods.stream()
+                .map(KwcContractTradeGoods::getGoodsId)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toSet());
+
+        // 通过GoodsInfoService获取商品信息
+        Map<Long, KwpGoods> goodsMap = new HashMap<>();
+        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(goodsIds)) {
+            Map<Long, KwpGoods> goodsByIds = goodsInfoService.getGoodsByIds(new ArrayList<>(goodsIds));
+            if (goodsByIds != null) {
+                goodsMap.putAll(goodsByIds);
+            }
+        }
+
+        Map<Long, SalesReportGoodsResVo> resultMap = new java.util.LinkedHashMap<>();
+        for (KwcContractTradeGoods goods : tradeGoods) {
+            Long goodsId = goods.getGoodsId();
+            if (goodsId == null) {
+                continue;
+            }
+
+            KwpGoods kwpGoods = goodsMap.get(goodsId);
+            if (kwpGoods == null) {
+                continue;
+            }
+
+            String name = kwpGoods.getName();
+
+            if (!resultMap.containsKey(goodsId)) {
+                SalesReportGoodsResVo resVo = new SalesReportGoodsResVo();
+                resVo.setGoodsId(goodsId);
+                resVo.setGoodsName(name);
+                resultMap.put(goodsId, resVo);
+            }
+        }
+
+        resVos.addAll(resultMap.values());
+        return resVos;
+    }
+
     @NotNull
     private static QueryListResVo getQueryListResVo(KwcContractTrade t,
                                                     Map<String, KwcContractTradeUnit> finalContractUnitTypeKeyAndUnitMap,

+ 15 - 0
sckw-modules/sckw-order/src/main/java/com/sckw/order/controller/KwoTradeOrderStatisticsController.java

@@ -1,6 +1,9 @@
 package com.sckw.order.controller;
 
+import com.sckw.core.web.response.BaseResult;
 import com.sckw.core.web.response.HttpResult;
+import com.sckw.order.api.model.SalesReportDataVo;
+import com.sckw.order.api.model.SalesReportQueryDto;
 import com.sckw.order.model.vo.req.WbTOrderDataStsParam;
 import com.sckw.order.model.vo.req.WbTOrderExcelStsParam;
 import com.sckw.order.serivce.KwoTradeOrderStatisticsService;
@@ -9,6 +12,8 @@ import org.springframework.http.MediaType;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
+import java.util.List;
+
 /**
  * @desc: 订单统计相关接口
  * @author: yzc
@@ -56,4 +61,14 @@ public class KwoTradeOrderStatisticsController {
     public HttpResult workbenchPurchaseList() {
         return HttpResult.ok(kwoTradeOrderStatisticsService.workbenchPurchaseList());
     }
+    /**
+     * 查询销售报表数据
+     *
+     * @param queryDto 查询参数
+     * @return 销售报表数据列表
+     */
+    @PostMapping("/querySalesReportData")
+    public BaseResult<List<SalesReportDataVo>> querySalesReportData(@RequestBody @Validated SalesReportQueryDto queryDto) {
+        return BaseResult.success(kwoTradeOrderStatisticsService.querySalesReportData(queryDto));
+    }
 }

+ 12 - 0
sckw-modules/sckw-order/src/main/java/com/sckw/order/dao/KwoTradeOrderMapper.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.sckw.core.model.vo.TableTop;
 import com.sckw.order.api.model.*;
 import com.sckw.order.model.KwoTradeOrder;
+import com.sckw.order.model.SalesReportRawData;
 import com.sckw.order.model.dto.*;
 import com.sckw.order.model.vo.res.TradeOrderAppStatisticVO;
 import org.apache.ibatis.annotations.Mapper;
@@ -160,4 +161,15 @@ public interface KwoTradeOrderMapper extends BaseMapper<KwoTradeOrder> {
     List<GoodsVo> countGoods(@Param("para") CountPara countPara, @Param("ids") List<Long> ids);
 
     List<TradeBuyVo> buyRank(@Param("para") CountPara countPara, @Param("ids") List<Long> ids);
+
+    /**
+     * 查询销售报表原始数据
+     * @param curEntId 当前企业ID
+     * @param customerId 客户ID
+     * @param goodsId 商品ID
+     * @return 销售报表原始数据列表
+     */
+    List<SalesReportRawData> querySalesReportRawData(@Param("curEntId") Long curEntId,
+                                                     @Param("customerId") Long customerId,
+                                                     @Param("goodsId") Long goodsId);
 }

+ 18 - 0
sckw-modules/sckw-order/src/main/java/com/sckw/order/model/SalesReportRawData.java

@@ -0,0 +1,18 @@
+package com.sckw.order.model;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 销售报表原始数据
+ */
+@Data
+public class SalesReportRawData {
+    private Long customerId;
+    private String customerName;
+    private Long goodsId;
+    private BigDecimal amount;
+    private BigDecimal price;
+    private String createTime;
+}

+ 99 - 0
sckw-modules/sckw-order/src/main/java/com/sckw/order/serivce/KwoTradeOrderStatisticsService.java

@@ -8,9 +8,13 @@ import com.sckw.core.model.constant.Global;
 import com.sckw.core.model.constant.NumberConstant;
 import com.sckw.core.utils.BeanUtils;
 import com.sckw.core.utils.DateUtils;
+import com.sckw.core.utils.StringUtils;
 import com.sckw.core.web.context.LoginUserHolder;
 import com.sckw.order.dao.KwoTradeOrderMapper;
+import com.sckw.order.model.SalesReportRawData;
 import com.sckw.order.model.dto.*;
+import com.sckw.order.api.model.SalesReportDataVo;
+import com.sckw.order.api.model.SalesReportQueryDto;
 import com.sckw.order.model.vo.req.WbTOrderDataStsParam;
 import com.sckw.order.model.vo.req.WbTOrderExcelStsParam;
 import com.sckw.order.model.vo.res.TOrderDataStsResVO;
@@ -26,6 +30,8 @@ import com.sckw.product.api.model.KwpGoods;
 import com.sckw.system.api.RemoteSystemService;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import java.util.*;
+import java.util.stream.Collectors;
 import org.apache.dubbo.config.annotation.DubboReference;
 import org.springframework.stereotype.Service;
 
@@ -313,5 +319,98 @@ public class KwoTradeOrderStatisticsService {
         }
         return d.setScale(2, RoundingMode.HALF_UP);
     }
+
+    /**
+     * 查询销售报表数据
+     *
+     * @param queryDto 查询参数
+     * @return 销售报表数据列表
+     */
+    public List<SalesReportDataVo> querySalesReportData(SalesReportQueryDto queryDto) {
+        // 1. 查询基础销售订单数据
+        List<SalesReportRawData> rawDataList = tradeOrderMapper.querySalesReportRawData(
+                queryDto.getCurEntId(),
+                queryDto.getCustomerId(),
+                queryDto.getGoodsId()
+        );
+        
+        // 2. 收集商品ID,获取商品名称
+        List<Long> goodsIds = rawDataList.stream()
+                .map(SalesReportRawData::getGoodsId)
+                .filter(Objects::nonNull)
+                .distinct()
+                .collect(Collectors.toList());
+        
+        // 3. 调用商品服务获取商品名称
+        Map<Long, KwpGoods> goodsMap = new HashMap<>();
+        if (!goodsIds.isEmpty()) {
+            goodsMap = goodsInfoService.getGoodsByIds(goodsIds);
+        }
+        
+        // 4. 按客户和商品分组汇总数据
+        Map<Long, Map<Long, SalesReportDataVo>> customerGoodsMap = new HashMap<>();
+        
+        for (SalesReportRawData rawData : rawDataList) {
+            Long customerId = rawData.getCustomerId();
+            Long goodsId = rawData.getGoodsId();
+            BigDecimal amount = rawData.getAmount();
+            BigDecimal price = rawData.getPrice();
+            String createTime = rawData.getCreateTime();
+            
+            // 初始化客户和商品的映射
+            customerGoodsMap.putIfAbsent(customerId, new HashMap<>());
+            Map<Long, SalesReportDataVo> goodsMapForCustomer = customerGoodsMap.get(customerId);
+            
+            // 初始化销售报表数据对象
+            goodsMapForCustomer.putIfAbsent(goodsId, new SalesReportDataVo());
+            SalesReportDataVo vo = goodsMapForCustomer.get(goodsId);
+            
+            // 设置基本信息
+            vo.setCustomerId(customerId);
+            vo.setCustomerName(rawData.getCustomerName());
+            vo.setGoodsId(goodsId);
+            KwpGoods goods = goodsMap.get(goodsId);
+            if (goods != null) {
+                vo.setGoodsName(goods.getName());
+            }
+            
+            // 计算累计数据
+            if(StringUtils.isNotBlank(queryDto.getEndTime())){
+                if (createTime != null && createTime.compareTo(queryDto.getEndTime()) <= 0){
+                    vo.setCumulativeQuantity(vo.getCumulativeQuantity().add(amount));
+                    vo.setCumulativeAmount(vo.getCumulativeAmount().add(price));
+                    if (vo.getCumulativeQuantity().compareTo(BigDecimal.ZERO) > 0) {
+                        vo.setCumulativeAveragePrice(vo.getCumulativeAmount().divide(vo.getCumulativeQuantity(), 2, RoundingMode.HALF_UP));
+                    }
+                }
+            }else{
+                vo.setCumulativeQuantity(vo.getCumulativeQuantity().add(amount));
+                vo.setCumulativeAmount(vo.getCumulativeAmount().add(price));
+                if (vo.getCumulativeQuantity().compareTo(BigDecimal.ZERO) > 0) {
+                    vo.setCumulativeAveragePrice(vo.getCumulativeAmount().divide(vo.getCumulativeQuantity(), 2, RoundingMode.HALF_UP));
+                }
+            }
+            
+            // 计算当前时间段数据
+            if (createTime != null && createTime.compareTo(queryDto.getStartTime()) >= 0 && createTime.compareTo(queryDto.getEndTime()) <= 0) {
+                vo.setSalesQuantity(vo.getSalesQuantity().add(amount));
+                vo.setSalesAmount(vo.getSalesAmount().add(price));
+                if (vo.getSalesQuantity().compareTo(BigDecimal.ZERO) > 0) {
+                    vo.setAveragePrice(vo.getSalesAmount().divide(vo.getSalesQuantity(), 2, RoundingMode.HALF_UP));
+                }
+            }
+        }
+        
+        // 5. 转换为列表并返回
+        List<SalesReportDataVo> result = new ArrayList<>();
+        for (Map<Long, SalesReportDataVo> goodsMapForCustomer : customerGoodsMap.values()) {
+            result.addAll(goodsMapForCustomer.values());
+        }
+        
+        // 6. 排序
+        result.sort(Comparator.comparing(SalesReportDataVo::getCustomerName).thenComparing(SalesReportDataVo::getGoodsName));
+        
+        return result;
+    }
 }
 

+ 21 - 0
sckw-modules/sckw-order/src/main/resources/mapper/KwoTradeOrderMapper.xml

@@ -866,6 +866,27 @@
         </where>
     </select>
 
+    <select id="querySalesReportRawData" resultType="com.sckw.order.model.SalesReportRawData">
+        select d.ent_id as customerId,
+               d.firm_name as customerName,
+               ktog.goods_id as goodsId,
+               kto.amount as amount,
+               kto.price as price,
+               DATE_FORMAT(kto.create_time, '%Y-%m-%d') as createTime
+        from kwo_trade_order kto
+                 inner join kwo_trade_order_unit d on kto.id = d.t_order_id and d.unit_type = '1' and d.del_flag = 0
+                 inner join kwo_trade_order_unit e on kto.id = e.t_order_id and e.unit_type = '2' and e.del_flag = 0
+                 inner join kwo_trade_order_goods ktog on kto.id = ktog.t_order_id and ktog.del_flag = 0
+        where kto.del_flag = 0
+          and e.ent_id = #{curEntId}
+          <if test="customerId != null">
+              and d.ent_id = #{customerId}
+          </if>
+          <if test="goodsId != null">
+              and ktog.goods_id = #{goodsId}
+          </if>
+    </select>
+
     <select id="countList" resultType="com.sckw.order.api.model.TradeSaleVo">
         select ktog.goods_id,
                CONCAT(

+ 77 - 0
sckw-modules/sckw-report/src/main/java/com/sckw/report/controller/KwSalesReportController.java

@@ -0,0 +1,77 @@
+package com.sckw.report.controller;
+
+import com.sckw.report.model.dto.SalesReportDTO;
+import com.sckw.report.model.vo.CustomerVO;
+import com.sckw.report.model.vo.ProductVO;
+import com.sckw.report.model.vo.SalesReportVO;
+import com.sckw.report.model.vo.SalesReportSummaryVO;
+import com.sckw.report.service.KwSalesReportService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/salesReport")
+@Tag(name = "销售报表")
+public class KwSalesReportController {
+
+    @Autowired
+    private KwSalesReportService salesReportService;
+
+    /**
+     * 获取销售报表数据
+     * @param salesReportDTO 筛选参数
+     * @return 报表数据列表
+     */
+    @PostMapping("/getSalesReportData")
+    @Operation(summary = "获取销售报表数据", description = "根据筛选参数获取销售报表数据列表")
+    public List<SalesReportVO> getSalesReportData(@RequestBody SalesReportDTO salesReportDTO) {
+        return salesReportService.getSalesReportData(salesReportDTO);
+    }
+
+    /**
+     * 获取销售报表汇总数据
+     * @param salesReportDTO 筛选参数
+     * @return 汇总数据
+     */
+    @PostMapping("/summary")
+    @Operation(summary = "获取销售报表汇总数据", description = "根据筛选参数获取销售报表汇总数据")
+    public SalesReportSummaryVO getSalesReportSummary(@RequestBody SalesReportDTO salesReportDTO) {
+        return salesReportService.getSalesReportSummary(salesReportDTO);
+    }
+
+    /**
+     * 导出销售报表
+     * @param salesReportDTO 筛选参数
+     * @param response 响应对象
+     */
+    @PostMapping("/export")
+    @Operation(summary = "导出销售报表", description = "根据筛选参数导出销售报表")
+    public void exportSalesReport(@RequestBody SalesReportDTO salesReportDTO, HttpServletResponse response) {
+        salesReportService.exportSalesReport(salesReportDTO, response);
+    }
+
+    /**
+     * 获取所有客户名称
+     * @return 客户名称列表
+     */
+    @GetMapping("/customers")
+    @Operation(summary = "获取所有客户名称", description = "获取所有客户名称列表")
+    public List<CustomerVO> getAllCustomers() {
+        return salesReportService.getAllCustomers();
+    }
+
+    /**
+     * 获取所有商品名称
+     * @return 商品名称列表
+     */
+    @GetMapping("/products")
+    @Operation(summary = "获取所有商品名称", description = "获取所有商品名称列表")
+    public List<ProductVO> getAllProducts() {
+        return salesReportService.getAllProducts();
+    }
+}

+ 36 - 0
sckw-modules/sckw-report/src/main/java/com/sckw/report/model/dto/SalesReportDTO.java

@@ -0,0 +1,36 @@
+package com.sckw.report.model.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+import java.util.Date;
+
+@Data
+@Schema(description = "销售报表筛选参数")
+public class SalesReportDTO {
+
+    /**
+     * 客户企业id
+     */
+    @Schema(description = "客户企业id")
+    private Long customerId;
+
+    /**
+     * 商品id
+     */
+    @Schema(description = "商品id")
+    private Long productId;
+
+    /**
+     * 开始时间
+     */
+    @Schema(description = "开始时间")
+    private Date startTime;
+
+    /**
+     * 结束时间
+     */
+    @Schema(description = "结束时间")
+    private Date endTime;
+}

+ 18 - 0
sckw-modules/sckw-report/src/main/java/com/sckw/report/model/vo/CustomerVO.java

@@ -0,0 +1,18 @@
+package com.sckw.report.model.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+@Schema(description = "客户信息")
+public class CustomerVO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @Schema(description = "客户id")
+    private Long customerId;
+
+    @Schema(description = "客户名称")
+    private String customerName;
+}

+ 18 - 0
sckw-modules/sckw-report/src/main/java/com/sckw/report/model/vo/ProductVO.java

@@ -0,0 +1,18 @@
+package com.sckw.report.model.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+@Schema(description = "商品信息")
+public class ProductVO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @Schema(description = "商品id")
+    private Long productId;
+
+    @Schema(description = "商品名称")
+    private String productName;
+}

+ 35 - 0
sckw-modules/sckw-report/src/main/java/com/sckw/report/model/vo/SalesReportSummaryVO.java

@@ -0,0 +1,35 @@
+package com.sckw.report.model.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+@Schema(description = "销售报表汇总数据")
+public class SalesReportSummaryVO {
+
+    /**
+     * 销售数量合计(吨)
+     */
+    @Schema(description = "销售数量合计(吨)")
+    private BigDecimal totalSalesQuantity;
+
+    /**
+     * 销售额合计(元)
+     */
+    @Schema(description = "销售额合计(元)")
+    private BigDecimal totalSalesAmount;
+
+    /**
+     * 累计销售数量合计(吨)
+     */
+    @Schema(description = "累计销售数量合计(吨)")
+    private BigDecimal totalTotalSalesQuantity;
+
+    /**
+     * 累计销售额合计(元)
+     */
+    @Schema(description = "累计销售额合计(元)")
+    private BigDecimal totalTotalSalesAmount;
+}

+ 77 - 0
sckw-modules/sckw-report/src/main/java/com/sckw/report/model/vo/SalesReportVO.java

@@ -0,0 +1,77 @@
+package com.sckw.report.model.vo;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.sckw.excel.annotation.ExcelContext;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+@ExcelContext(fileName = "销售报表", sheetName = "销售数据")
+@Schema(description = "销售报表数据")
+public class SalesReportVO {
+
+    /**
+     * 序号
+     */
+    @ExcelProperty(value = "序号", index = 0)
+    @Schema(description = "序号")
+    private Integer serialNumber;
+
+    /**
+     * 客户名称
+     */
+    @ExcelProperty(value = "客户名称", index = 1)
+    @Schema(description = "客户名称")
+    private String customerName;
+
+    /**
+     * 商品名称
+     */
+    @ExcelProperty(value = "商品名称", index = 2)
+    @Schema(description = "商品名称")
+    private String productName;
+
+    /**
+     * 销售数量(吨)
+     */
+    @ExcelProperty(value = "销售数量(吨)", index = 3)
+    @Schema(description = "销售数量(吨)")
+    private BigDecimal salesQuantity;
+
+    /**
+     * 销售平均单价(元/吨)
+     */
+    @ExcelProperty(value = "销售平均单价(元/吨)", index = 4)
+    @Schema(description = "销售平均单价(元/吨)")
+    private BigDecimal averagePrice;
+
+    /**
+     * 销售额(元)
+     */
+    @ExcelProperty(value = "本月销售额(元)", index = 5)
+    @Schema(description = "本月销售额(元)")
+    private BigDecimal salesAmount;
+
+    /**
+     * 累计销售数量(吨)
+     */
+    @ExcelProperty(value = "累计销售数量(吨)", index = 6)
+    @Schema(description = "累计销售数量(吨)")
+    private BigDecimal totalSalesQuantity;
+
+    /**
+     * 累计平均销售单价(元/吨)
+     */
+    @ExcelProperty(value = "累计平均销售单价(元/吨)", index = 7)
+    @Schema(description = "累计平均销售单价(元/吨)")
+    private BigDecimal totalAveragePrice;
+
+    /**
+     * 累计销售额(元)
+     */
+    @ExcelProperty(value = "累计销售额(元)", index = 8)
+    @Schema(description = "累计销售额(元)")
+    private BigDecimal totalSalesAmount;
+}

+ 46 - 0
sckw-modules/sckw-report/src/main/java/com/sckw/report/service/KwSalesReportService.java

@@ -0,0 +1,46 @@
+package com.sckw.report.service;
+
+import com.sckw.report.model.dto.SalesReportDTO;
+import com.sckw.report.model.vo.CustomerVO;
+import com.sckw.report.model.vo.ProductVO;
+import com.sckw.report.model.vo.SalesReportVO;
+import com.sckw.report.model.vo.SalesReportSummaryVO;
+import jakarta.servlet.http.HttpServletResponse;
+
+import java.util.List;
+
+public interface KwSalesReportService {
+
+    /**
+     * 获取销售报表数据
+     * @param salesReportDTO 筛选参数
+     * @return 报表数据列表
+     */
+    List<SalesReportVO> getSalesReportData(SalesReportDTO salesReportDTO);
+
+    /**
+     * 获取销售报表汇总数据
+     * @param salesReportDTO 筛选参数
+     * @return 汇总数据
+     */
+    SalesReportSummaryVO getSalesReportSummary(SalesReportDTO salesReportDTO);
+
+    /**
+     * 导出销售报表
+     * @param salesReportDTO 筛选参数
+     * @param response 响应对象
+     */
+    void exportSalesReport(SalesReportDTO salesReportDTO, HttpServletResponse response);
+
+    /**
+     * 获取所有客户名称
+     * @return 客户名称列表
+     */
+    List<CustomerVO> getAllCustomers();
+
+    /**
+     * 获取所有商品名称
+     * @return 商品名称列表
+     */
+    List<ProductVO> getAllProducts();
+}

+ 148 - 0
sckw-modules/sckw-report/src/main/java/com/sckw/report/service/impl/KwSalesReportServiceImpl.java

@@ -0,0 +1,148 @@
+package com.sckw.report.service.impl;
+
+import com.sckw.contract.api.feign.SalesReportContractFeignService;
+import com.sckw.contract.api.model.dto.req.SalesReportGoodsQueryDto;
+import com.sckw.contract.api.model.dto.req.TradeEntListQueryFeignDto;
+import com.sckw.contract.api.model.dto.res.SalesReportGoodsResVo;
+import com.sckw.contract.api.model.dto.res.TradeEntInfoResVo;
+import com.sckw.core.web.context.LoginUserHolder;
+import com.sckw.core.web.response.BaseResult;
+import com.sckw.excel.utils.ExcelUtil;
+import com.sckw.order.api.feign.SalesReportOrderFeignService;
+import com.sckw.order.api.model.SalesReportDataVo;
+import com.sckw.order.api.model.SalesReportQueryDto;
+import com.sckw.report.model.dto.SalesReportDTO;
+import com.sckw.report.model.vo.CustomerVO;
+import com.sckw.report.model.vo.ProductVO;
+import com.sckw.report.model.vo.SalesReportVO;
+import com.sckw.report.model.vo.SalesReportSummaryVO;
+import com.sckw.report.service.KwSalesReportService;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+
+@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
+@Service
+@RequiredArgsConstructor
+public class KwSalesReportServiceImpl implements KwSalesReportService {
+
+    private  static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+
+    @Autowired
+    private SalesReportContractFeignService salesReportContractFeignService;
+    @Autowired
+    private SalesReportOrderFeignService salesReportOrderFeignService;
+
+    @Override
+    public List<SalesReportVO> getSalesReportData(SalesReportDTO salesReportDTO) {
+        // 调用订单服务获取销售报表数据
+        SalesReportQueryDto queryDto = new SalesReportQueryDto();
+        queryDto.setCurEntId(LoginUserHolder.getEntId());
+        queryDto.setCustomerId(salesReportDTO.getCustomerId());
+        queryDto.setGoodsId(salesReportDTO.getProductId());
+        
+        // 转换时间格式:Date转String yyyy-MM-dd
+        if (salesReportDTO.getStartTime() != null) {
+            queryDto.setStartTime(sdf.format(salesReportDTO.getStartTime()));
+        }
+        if (salesReportDTO.getEndTime() != null) {
+            queryDto.setEndTime(sdf.format(salesReportDTO.getEndTime()));
+        }
+
+        BaseResult<List<SalesReportDataVo>> result = salesReportOrderFeignService.querySalesReportData(queryDto);
+        if (result != null && result.isSuccess() && result.getData() != null) {
+            List<SalesReportDataVo> salesReportData = result.getData();
+            // 转换为销售报表VO
+            AtomicInteger serialNumber = new AtomicInteger(1);
+            return salesReportData.stream().map(data -> {
+                SalesReportVO vo = new SalesReportVO();
+                vo.setSerialNumber(serialNumber.getAndIncrement());
+                vo.setCustomerName(data.getCustomerName());
+                vo.setProductName(data.getGoodsName());
+                vo.setSalesQuantity(data.getSalesQuantity());
+                vo.setAveragePrice(data.getAveragePrice());
+                vo.setSalesAmount(data.getSalesAmount());
+                vo.setTotalSalesQuantity(data.getCumulativeQuantity());
+                vo.setTotalAveragePrice(data.getCumulativeAveragePrice());
+                vo.setTotalSalesAmount(data.getCumulativeAmount());
+                return vo;
+            }).collect(Collectors.toList());
+        }
+        return new ArrayList<>();
+    }
+
+    @Override
+    public SalesReportSummaryVO getSalesReportSummary(SalesReportDTO salesReportDTO) {
+        List<SalesReportVO> reportData = getSalesReportData(salesReportDTO);
+        SalesReportSummaryVO summary = new SalesReportSummaryVO();
+        
+        BigDecimal totalSalesQuantity = BigDecimal.ZERO;
+        BigDecimal totalSalesAmount = BigDecimal.ZERO;
+        BigDecimal totalTotalSalesQuantity = BigDecimal.ZERO;
+        BigDecimal totalTotalSalesAmount = BigDecimal.ZERO;
+        
+        for (SalesReportVO vo : reportData) {
+            totalSalesQuantity = totalSalesQuantity.add(vo.getSalesQuantity());
+            totalSalesAmount = totalSalesAmount.add(vo.getSalesAmount());
+            totalTotalSalesQuantity = totalTotalSalesQuantity.add(vo.getTotalSalesQuantity());
+            totalTotalSalesAmount = totalTotalSalesAmount.add(vo.getTotalSalesAmount());
+        }
+        
+        summary.setTotalSalesQuantity(totalSalesQuantity);
+        summary.setTotalSalesAmount(totalSalesAmount);
+        summary.setTotalTotalSalesQuantity(totalTotalSalesQuantity);
+        summary.setTotalTotalSalesAmount(totalTotalSalesAmount);
+        
+        return summary;
+    }
+
+    @Override
+    public void exportSalesReport(SalesReportDTO salesReportDTO, HttpServletResponse response) {
+        List<SalesReportVO> reportData = getSalesReportData(salesReportDTO);
+        
+        // 导出Excel
+        ExcelUtil.download(response, SalesReportVO.class, reportData);
+    }
+
+    @Override
+    public List<CustomerVO> getAllCustomers() {
+        TradeEntListQueryFeignDto queryDto = new TradeEntListQueryFeignDto();
+        queryDto.setCurEntId(LoginUserHolder.getEntId());
+        BaseResult<List<TradeEntInfoResVo>> result = salesReportContractFeignService.queryTradeEntList(queryDto);
+        if (result != null && result.isSuccess() && result.getData() != null) {
+            List<TradeEntInfoResVo> customerList =  result.getData();
+            return customerList.stream().map(customer -> {
+                CustomerVO vo = new CustomerVO();
+                vo.setCustomerId(customer.getEntId());
+                vo.setCustomerName(customer.getEntName());
+                return vo;
+            }).collect(Collectors.toList());
+        }
+        return new ArrayList<>();
+    }
+
+    @Override
+    public List<ProductVO> getAllProducts() {
+        SalesReportGoodsQueryDto queryDto = new SalesReportGoodsQueryDto();
+        queryDto.setCurEntId(LoginUserHolder.getEntId());
+        BaseResult<List<SalesReportGoodsResVo>> result = salesReportContractFeignService.queryGoodsList(queryDto);
+        if (result != null && result.isSuccess() && result.getData() != null) {
+            List<SalesReportGoodsResVo> goodsList = result.getData();
+            return goodsList.stream().map(goods -> {
+                ProductVO vo = new ProductVO();
+                vo.setProductId(goods.getGoodsId());
+                vo.setProductName(goods.getGoodsName());
+                return vo;
+            }).collect(Collectors.toList());
+        }
+        return new ArrayList<>();
+    }
+}