소스 검색

销售管理模块后端代码

lbyzx123 4 일 전
부모
커밋
8020da6c96

+ 327 - 2
ruoyi-admin/src/main/java/com/ruoyi/web/sales/controller/SalesOrderController.java

@@ -15,11 +15,13 @@ import com.ruoyi.web.base.service.IBaseLineService;
 import com.ruoyi.web.base.service.IBaseMaterialService;
 import com.ruoyi.web.base.service.IBaseMarketService;
 import com.ruoyi.web.sales.domain.*;
+import com.ruoyi.web.sales.mapper.SalesOrderGoodsMapper;
 import com.ruoyi.web.sales.service.*;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.format.annotation.DateTimeFormat;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
 
@@ -32,8 +34,10 @@ import java.time.LocalDate;
 import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -49,11 +53,16 @@ import static com.ruoyi.common.utils.SecurityUtils.getUsername;
 @RequestMapping("/sales-order")
 public class SalesOrderController {
 
+    /** MySQL 等数据库对 IN 列表过大时性能差,分批查询 */
+    private static final int SQL_IN_BATCH_SIZE = 800;
+
     @Autowired
     private ISalesOrderService salesOrderService;
     @Autowired
     private ISalesOrderGoodsService salesOrderGoodsService;
     @Autowired
+    private SalesOrderGoodsMapper salesOrderGoodsMapper;
+    @Autowired
     private IBaseCustomerService customerService;
     @Autowired
     private IRelCustomerMarketService relCustomerMarketService;
@@ -190,8 +199,25 @@ public class SalesOrderController {
 
     @ApiOperation("销售订单列表")
     @PostMapping("/list")
-    public AjaxResult list(@RequestBody SalesOrder query, HttpServletRequest request) {
+    public AjaxResult list(@RequestBody(required = false) SalesOrder query, HttpServletRequest request) {
         String orgId = tokenService.getLoginOrgId(request);
+        if (query == null) {
+            query = new SalesOrder();
+        }
+        if (StringUtils.isBlank(query.getCustomerNum())) {
+            query.setCustomerNum(firstNonBlank(
+                    request.getParameter("customerNum"),
+                    request.getParameter("customer_no"),
+                    request.getParameter("customerNo")
+            ));
+        }
+        if (StringUtils.isBlank(query.getEmployeeNum())) {
+            query.setEmployeeNum(firstNonBlank(
+                    request.getParameter("employeeNum"),
+                    request.getParameter("employee_no"),
+                    request.getParameter("employeeNo")
+            ));
+        }
         List<SalesOrder> list = salesOrderService.list(buildWrapper(query, orgId));
         for (SalesOrder row : list) {
             enrichSalesOrderDisplay(row, orgId);
@@ -211,6 +237,27 @@ public class SalesOrderController {
         util.exportExcel(response, list, "销售订单");
     }
 
+    @ApiOperation("销售订单货品明细列表")
+    @PostMapping("/goodsDetailList")
+    public AjaxResult goodsDetailList(@RequestBody Map<String, String> params, HttpServletRequest request) throws Exception {
+        String saleDate = params == null ? null : params.get("saleDate");
+        if (StringUtils.isBlank(saleDate)) {
+            throw new Exception("销售日期不能为空");
+        }
+        String orgId = tokenService.getLoginOrgId(request);
+        String lineNum = params.get("lineNum");
+        String marketNum = params.get("marketNum");
+        String customerNum = params.get("customerNum");
+        List<Map<String, Object>> list = salesOrderGoodsMapper.listGoodsDetailByConditions(
+                orgId,
+                saleDate.trim(),
+                StringUtils.isBlank(lineNum) ? null : lineNum.trim(),
+                StringUtils.isBlank(marketNum) ? null : marketNum.trim(),
+                StringUtils.isBlank(customerNum) ? null : customerNum.trim()
+        );
+        return success(list);
+    }
+
     @ApiOperation("销售订单审核")
     @PostMapping("/audit")
     public AjaxResult audit(@RequestBody Map<String, String> params) throws Exception {
@@ -436,6 +483,281 @@ public class SalesOrderController {
         return success(tree);
     }
 
+    @ApiOperation("物流线-市场-客户三级树(按销售日期和产品类型统计goodsCount)")
+    @GetMapping("/lineMarketCustomerStats")
+    public AjaxResult lineMarketCustomerStats(
+            @ApiParam(value = "销售日期(yyyy-MM-dd)", required = true)
+            @RequestParam("saleDate")
+            @DateTimeFormat(pattern = "yyyy-MM-dd") Date saleDate,
+            @ApiParam(value = "产品类型(productType),不传默认002")
+            @RequestParam(value = "productType", required = false) String productType,
+            HttpServletRequest request) {
+        if (saleDate == null) {
+            return AjaxResult.error("销售日期不能为空");
+        }
+        String statProductType = StringUtils.isBlank(productType) ? "002" : productType.trim();
+        String orgId = tokenService.getLoginOrgId(request);
+
+        List<SalesOrder> saleDateOrders = salesOrderService.list(new QueryWrapper<SalesOrder>()
+                .eq("org_id", orgId)
+                .eq("del_flag", "0")
+                .eq("sale_date", saleDate)
+                .orderByDesc("id"));
+        if (saleDateOrders == null || saleDateOrders.isEmpty()) {
+            return success(new ArrayList<Map<String, Object>>());
+        }
+        Set<String> orderNums = saleDateOrders.stream()
+                .map(SalesOrder::getOrderNum)
+                .filter(StringUtils::isNotBlank)
+                .map(String::trim)
+                .collect(Collectors.toCollection(LinkedHashSet::new));
+        if (orderNums.isEmpty()) {
+            return success(new ArrayList<Map<String, Object>>());
+        }
+        Map<String, String> customerByOrderNum = saleDateOrders.stream()
+                .filter(o -> StringUtils.isNotBlank(o.getOrderNum()) && StringUtils.isNotBlank(o.getCustomerNum()))
+                .collect(Collectors.toMap(o -> o.getOrderNum().trim(), o -> o.getCustomerNum().trim(), (a, b) -> a, LinkedHashMap::new));
+        Set<String> orderCustomers = new LinkedHashSet<String>(customerByOrderNum.values());
+        if (orderCustomers.isEmpty()) {
+            return success(new ArrayList<Map<String, Object>>());
+        }
+
+        List<SalesOrderGoods> orderGoodsList = new ArrayList<SalesOrderGoods>();
+        for (List<String> batch : partitionList(new ArrayList<String>(orderNums), SQL_IN_BATCH_SIZE)) {
+            orderGoodsList.addAll(salesOrderGoodsService.list(new QueryWrapper<SalesOrderGoods>()
+                    .eq("org_id", orgId)
+                    .eq("del_flag", "0")
+                    .in("order_num", batch)));
+        }
+        Set<String> goodsNums = orderGoodsList.stream()
+                .map(SalesOrderGoods::getGoodsNum)
+                .filter(StringUtils::isNotBlank)
+                .map(String::trim)
+                .collect(Collectors.toCollection(LinkedHashSet::new));
+        Set<String> allowedGoodsNums = new LinkedHashSet<String>();
+        if (!goodsNums.isEmpty()) {
+            List<String> goodsNumList = new ArrayList<String>(goodsNums);
+            for (List<String> batch : partitionList(goodsNumList, SQL_IN_BATCH_SIZE)) {
+                List<BaseMaterial> materials = baseMaterialService.list(new QueryWrapper<BaseMaterial>()
+                        .eq("org_id", orgId)
+                        .eq("del_flag", "0")
+                        .eq("product_type", statProductType)
+                        .in("goods_num", batch));
+                for (BaseMaterial m : materials) {
+                    if (m != null && StringUtils.isNotBlank(m.getGoodsNum())) {
+                        allowedGoodsNums.add(m.getGoodsNum().trim());
+                    }
+                }
+            }
+        }
+
+        Map<String, BigDecimal> customerGoodsCountMap = new LinkedHashMap<String, BigDecimal>();
+        for (String customerNum : orderCustomers) {
+            customerGoodsCountMap.put(customerNum, BigDecimal.ZERO);
+        }
+        for (SalesOrderGoods goods : orderGoodsList) {
+            if (goods == null || StringUtils.isBlank(goods.getOrderNum()) || StringUtils.isBlank(goods.getGoodsNum())) {
+                continue;
+            }
+            String goodsNum = goods.getGoodsNum().trim();
+            if (!allowedGoodsNums.contains(goodsNum)) {
+                continue;
+            }
+            String customerNum = customerByOrderNum.get(goods.getOrderNum().trim());
+            if (StringUtils.isBlank(customerNum)) {
+                continue;
+            }
+            BigDecimal qty = parseMoney(goods.getAssNum());
+            customerGoodsCountMap.put(customerNum, customerGoodsCountMap.getOrDefault(customerNum, BigDecimal.ZERO).add(qty == null ? BigDecimal.ZERO : qty));
+        }
+
+        List<RelCustomerMarket> allRels = new ArrayList<RelCustomerMarket>();
+        List<String> customerList = new ArrayList<String>(orderCustomers);
+        for (List<String> batch : partitionList(customerList, SQL_IN_BATCH_SIZE)) {
+            allRels.addAll(relCustomerMarketService.list(new QueryWrapper<RelCustomerMarket>()
+                    .eq("org_id", orgId)
+                    .and(w -> w.eq("del_flag", "0").or().isNull("del_flag"))
+                    .in("customer_num", batch)
+                    .orderByDesc("id")));
+        }
+        if (allRels.isEmpty()) {
+            return success(new ArrayList<Map<String, Object>>());
+        }
+
+        LinkedHashSet<String> relLineNums = new LinkedHashSet<String>();
+        HashSet<String> relPairs = new HashSet<String>();
+        for (RelCustomerMarket r : allRels) {
+            if (r == null || StringUtils.isBlank(r.getLineNum()) || StringUtils.isBlank(r.getMarketNum())) {
+                continue;
+            }
+            String ln = r.getLineNum().trim();
+            String mn = r.getMarketNum().trim();
+            relLineNums.add(ln);
+            relPairs.add(ln + "\0" + mn);
+        }
+        if (relLineNums.isEmpty()) {
+            return success(new ArrayList<Map<String, Object>>());
+        }
+
+        List<BaseLine> lines = new ArrayList<BaseLine>();
+        Map<String, BaseLine> lineByNum = new LinkedHashMap<String, BaseLine>();
+        for (List<String> batch : partitionList(new ArrayList<String>(relLineNums), SQL_IN_BATCH_SIZE)) {
+            List<BaseLine> chunk = baseLineService.list(new QueryWrapper<BaseLine>()
+                    .eq("org_id", orgId)
+                    .in("line_num", batch)
+                    .and(w -> w.eq("del_flag", "0").or().isNull("del_flag"))
+                    .orderByAsc("line_num")
+                    .orderByAsc("id"));
+            for (BaseLine line : chunk) {
+                if (line != null && StringUtils.isNotBlank(line.getLineNum())) {
+                    String k = line.getLineNum().trim();
+                    lineByNum.putIfAbsent(k, line);
+                }
+            }
+        }
+        lines.addAll(lineByNum.values());
+        lines.sort(Comparator.comparing(l -> l.getLineNum() == null ? "" : l.getLineNum().trim()));
+
+        Map<String, BaseMarket> marketDedupe = new LinkedHashMap<String, BaseMarket>();
+        for (List<String> batch : partitionList(new ArrayList<String>(relLineNums), SQL_IN_BATCH_SIZE)) {
+            List<BaseMarket> chunk = baseMarketService.list(new QueryWrapper<BaseMarket>()
+                    .eq("org_id", orgId)
+                    .in("line_num", batch)
+                    .and(w -> w.eq("del_flag", "0").or().isNull("del_flag"))
+                    .orderByAsc("market_num")
+                    .orderByAsc("id"));
+            for (BaseMarket m : chunk) {
+                if (m == null || StringUtils.isBlank(m.getLineNum()) || StringUtils.isBlank(m.getMarketNum())) {
+                    continue;
+                }
+                String ln = m.getLineNum().trim();
+                String mn = m.getMarketNum().trim();
+                if (!relPairs.contains(ln + "\0" + mn)) {
+                    continue;
+                }
+                String mk = ln + "\0" + mn;
+                marketDedupe.putIfAbsent(mk, m);
+            }
+        }
+        Map<String, List<BaseMarket>> marketsByLineNum = marketDedupe.values().stream()
+                .filter(m -> StringUtils.isNotBlank(m.getLineNum()))
+                .collect(Collectors.groupingBy(m -> m.getLineNum().trim(), LinkedHashMap::new, Collectors.toList()));
+
+        List<BaseCustomer> customers = new ArrayList<BaseCustomer>();
+        for (List<String> batch : partitionList(customerList, SQL_IN_BATCH_SIZE)) {
+            customers.addAll(customerService.list(new QueryWrapper<BaseCustomer>()
+                    .eq("org_id", orgId)
+                    .and(w -> w.eq("del_flag", "0").or().isNull("del_flag"))
+                    .in("customer_num", batch)));
+        }
+        Map<String, String> customerNameMap = customers.stream()
+                .filter(c -> StringUtils.isNotBlank(c.getCustomerNum()))
+                .collect(Collectors.toMap(BaseCustomer::getCustomerNum,
+                        c -> c.getCustomerName() != null ? c.getCustomerName() : "",
+                        (a, b) -> a, LinkedHashMap::new));
+
+        Map<String, List<RelCustomerMarket>> relsByLineAndMarket = new LinkedHashMap<String, List<RelCustomerMarket>>();
+        for (RelCustomerMarket r : allRels) {
+            if (StringUtils.isBlank(r.getLineNum()) || StringUtils.isBlank(r.getMarketNum())) {
+                continue;
+            }
+            String key = r.getLineNum().trim() + "\0" + r.getMarketNum().trim();
+            relsByLineAndMarket.computeIfAbsent(key, k -> new ArrayList<RelCustomerMarket>()).add(r);
+        }
+
+        List<Map<String, Object>> tree = new ArrayList<Map<String, Object>>();
+        for (BaseLine line : lines) {
+            String lineNum = line.getLineNum() == null ? "" : line.getLineNum().trim();
+            Map<String, Object> lineNode = new LinkedHashMap<String, Object>();
+            lineNode.put("id", "line:" + lineNum + ":" + line.getId());
+            lineNode.put("label", StringUtils.isNotBlank(line.getLineName()) ? line.getLineName() : lineNum);
+            lineNode.put("type", "line");
+            lineNode.put("lineNum", lineNum);
+            lineNode.put("lineName", line.getLineName());
+
+            BigDecimal lineGoodsCount = BigDecimal.ZERO;
+            List<Map<String, Object>> marketChildren = new ArrayList<Map<String, Object>>();
+            List<BaseMarket> markets = marketsByLineNum.getOrDefault(lineNum, new ArrayList<BaseMarket>());
+            for (BaseMarket market : markets) {
+                String marketNum = market.getMarketNum() == null ? "" : market.getMarketNum().trim();
+                Map<String, Object> marketNode = new LinkedHashMap<String, Object>();
+                marketNode.put("id", "market:" + lineNum + ":" + marketNum + ":" + market.getId());
+                marketNode.put("label", StringUtils.isNotBlank(market.getMarketName()) ? market.getMarketName() : marketNum);
+                marketNode.put("type", "market");
+                marketNode.put("lineNum", lineNum);
+                marketNode.put("marketNum", marketNum);
+                marketNode.put("marketName", market.getMarketName());
+
+                BigDecimal marketGoodsCount = BigDecimal.ZERO;
+                String relKey = lineNum + "\0" + marketNum;
+                List<RelCustomerMarket> rels = relsByLineAndMarket.getOrDefault(relKey, new ArrayList<RelCustomerMarket>());
+                Set<String> seenCustomer = new LinkedHashSet<String>();
+                List<Map<String, Object>> customerChildren = new ArrayList<Map<String, Object>>();
+                for (RelCustomerMarket rel : rels) {
+                    String customerNum = rel.getCustomerNum() == null ? "" : rel.getCustomerNum().trim();
+                    if (StringUtils.isBlank(customerNum) || !seenCustomer.add(customerNum)) {
+                        continue;
+                    }
+                    BigDecimal customerGoodsCount = customerGoodsCountMap.getOrDefault(customerNum, BigDecimal.ZERO);
+                    String customerName = StringUtils.isNotBlank(rel.getCustomerName())
+                            ? rel.getCustomerName()
+                            : customerNameMap.getOrDefault(customerNum, customerNum);
+                    Map<String, Object> custNode = new LinkedHashMap<String, Object>();
+                    custNode.put("id", "customer:" + lineNum + ":" + marketNum + ":" + customerNum + ":" + rel.getId());
+                    custNode.put("label", customerName);
+                    custNode.put("type", "customer");
+                    custNode.put("lineNum", lineNum);
+                    custNode.put("marketNum", marketNum);
+                    custNode.put("customerNum", customerNum);
+                    custNode.put("customerName", customerName);
+                    custNode.put("relId", rel.getId());
+                    custNode.put("goodsCount", customerGoodsCount);
+                    custNode.put("leaf", true);
+                    customerChildren.add(custNode);
+                    marketGoodsCount = marketGoodsCount.add(customerGoodsCount);
+                }
+                if (customerChildren.isEmpty()) {
+                    continue;
+                }
+                marketNode.put("goodsCount", marketGoodsCount);
+                marketNode.put("children", customerChildren);
+                marketChildren.add(marketNode);
+                lineGoodsCount = lineGoodsCount.add(marketGoodsCount);
+            }
+            if (marketChildren.isEmpty()) {
+                continue;
+            }
+            lineNode.put("goodsCount", lineGoodsCount);
+            lineNode.put("children", marketChildren);
+            tree.add(lineNode);
+        }
+        return success(tree);
+    }
+
+    private static <T> List<List<T>> partitionList(List<T> list, int batchSize) {
+        if (list == null || list.isEmpty()) {
+            return Collections.emptyList();
+        }
+        int size = Math.max(1, batchSize);
+        List<List<T>> parts = new ArrayList<List<T>>();
+        for (int i = 0; i < list.size(); i += size) {
+            parts.add(list.subList(i, Math.min(i + size, list.size())));
+        }
+        return parts;
+    }
+
+    private String firstNonBlank(String... vals) {
+        if (vals == null || vals.length == 0) {
+            return null;
+        }
+        for (String v : vals) {
+            if (StringUtils.isNotBlank(v)) {
+                return v.trim();
+            }
+        }
+        return null;
+    }
+
     private QueryWrapper<SalesOrder> buildWrapper(SalesOrder query, String orgId) {
         QueryWrapper<SalesOrder> wrapper = new QueryWrapper<SalesOrder>()
                 .eq("org_id", orgId)
@@ -458,8 +780,11 @@ public class SalesOrderController {
         if (StringUtils.isNotBlank(query.getCustomerName())) {
             wrapper.like("customer_name", query.getCustomerName());
         }
+        if (StringUtils.isNotBlank(query.getCustomerNum())) {
+            wrapper.eq("customer_num", query.getCustomerNum().trim());
+        }
         if (StringUtils.isNotBlank(query.getEmployeeNum())) {
-            wrapper.like("employee_num", query.getEmployeeNum());
+            wrapper.eq("employee_num", query.getEmployeeNum().trim());
         }
         if (StringUtils.isNotBlank(query.getLineNum())) {
             wrapper.like("line_num", query.getLineNum());

+ 30 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/sales/mapper/SalesOrderGoodsMapper.java

@@ -2,6 +2,36 @@ package com.ruoyi.web.sales.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.ruoyi.web.sales.domain.SalesOrderGoods;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+import java.util.Map;
 
 public interface SalesOrderGoodsMapper extends BaseMapper<SalesOrderGoods> {
+
+    @Select({
+            "<script>",
+            "select sog.*, so.line_num, so.market_num, so.customer_num, so.customer_name, bm.variety, bm.variety_name, bm.goods_level ",
+            "from sales_order_goods sog, sales_order so, base_material bm ",
+            "where sog.order_num = so.order_num ",
+            "  and sog.goods_num = bm.goods_num ",
+            "  and sog.del_flag = '0' ",
+            "  and so.del_flag = '0' ",
+            "  and bm.del_flag = '0' ",
+            "  and so.org_id = #{orgId} ",
+            "  and sog.org_id = #{orgId} ",
+            "  and bm.org_id = #{orgId} ",
+            "  and so.sale_date = #{saleDate} ",
+            "  <if test='lineNum != null and lineNum != \"\"'> and so.line_num = #{lineNum} </if>",
+            "  <if test='marketNum != null and marketNum != \"\"'> and so.market_num = #{marketNum} </if>",
+            "  <if test='customerNum != null and customerNum != \"\"'> and so.customer_num = #{customerNum} </if>",
+            "order by so.id desc, sog.id asc",
+            "</script>"
+    })
+    List<Map<String, Object>> listGoodsDetailByConditions(@Param("orgId") String orgId,
+                                                          @Param("saleDate") String saleDate,
+                                                          @Param("lineNum") String lineNum,
+                                                          @Param("marketNum") String marketNum,
+                                                          @Param("customerNum") String customerNum);
 }