Parcourir la source

新增销售出库统计,周转率列表,无理由订单保存完成时间

fgd il y a 1 an
Parent
commit
72d5f93695

+ 35 - 0
sd-business/src/main/java/com/sd/business/controller/board/TurnoverRateBoardController.java

@@ -0,0 +1,35 @@
+package com.sd.business.controller.board;
+
+import com.sd.business.entity.board.vo.TurnoverRateStatisticsVo;
+import com.sd.business.service.order.OrderSalesShipmentStatisticsService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 周转率看板 前端控制器
+ * </p>
+ *
+ * @author
+ * @since 2023-10-20
+ */
+@RestController
+@RequestMapping("/turnoverRateBoard")
+public class TurnoverRateBoardController {
+    @Autowired
+    private OrderSalesShipmentStatisticsService orderSalesShipmentStatisticsService;
+
+    /**
+     * 获取周转率数据列表
+     * @return
+     */
+    @PostMapping("/getTurnoverRateStatisticsList")
+    public List<TurnoverRateStatisticsVo> getTurnoverRateStatisticsList() {
+        return orderSalesShipmentStatisticsService.getTurnoverRateStatisticsList();
+    }
+
+}

+ 32 - 0
sd-business/src/main/java/com/sd/business/entity/board/vo/TurnoverRateStatisticsVo.java

@@ -0,0 +1,32 @@
+package com.sd.business.entity.board.vo;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+
+/**
+ * 周转率统计数据查询返回值实体
+ *
+ * @since 2023-10-20
+ */
+@Getter
+@Setter
+public class TurnoverRateStatisticsVo {
+
+    /**
+     * 品号
+     */
+    private String bomSpecCode;
+
+    /**
+     * 品名
+     */
+    private String bomSpecName;
+
+    /**
+     * 周转率
+     */
+    private BigDecimal turnoverRate;
+}

+ 16 - 0
sd-business/src/main/java/com/sd/business/entity/order/dto/OrderSalesShipmentStatisticsDto.java

@@ -0,0 +1,16 @@
+package com.sd.business.entity.order.dto;
+
+import com.sd.business.entity.order.po.OrderSalesShipmentStatistics;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 订单销售出库统计 新增编辑入参实体
+ *
+ * @author
+ * @since 2023-10-20
+ */
+@Getter
+@Setter
+public class OrderSalesShipmentStatisticsDto extends OrderSalesShipmentStatistics {
+}

+ 38 - 0
sd-business/src/main/java/com/sd/business/entity/order/po/OrderSalesShipmentStatistics.java

@@ -0,0 +1,38 @@
+package com.sd.business.entity.order.po;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.ruoyi.common.core.domain.BasePo;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * <p>
+ * 订单销售出库统计
+ * </p>
+ *
+ * @author
+ * @since 2023-10-20
+ */
+@Getter
+@Setter
+@TableName("order_sales_shipment_statistics")
+public class OrderSalesShipmentStatistics extends BasePo {
+
+    /**
+     * 统计时间
+     */
+    private Date totalDate;
+
+    /**
+     * bom规格id
+     */
+    private Long bomSpecId;
+
+    /**
+     * 数量
+     */
+    private BigDecimal quantity;
+}

+ 26 - 0
sd-business/src/main/java/com/sd/business/entity/order/vo/OrderSalesShipmentStatisticsVo.java

@@ -0,0 +1,26 @@
+package com.sd.business.entity.order.vo;
+
+import com.sd.business.entity.order.po.OrderSalesShipmentStatistics;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 订单销售出库统计列表查询返回值实体
+ *
+ * @author
+ * @since 2023-10-20
+ */
+@Getter
+@Setter
+public class OrderSalesShipmentStatisticsVo extends OrderSalesShipmentStatistics {
+
+    /**
+     * 品号
+     */
+    private String bomSpecCode;
+
+    /**
+     * 品名
+     */
+    private String bomSpecName;
+}

+ 21 - 0
sd-business/src/main/java/com/sd/business/mapper/order/OrderSalesShipmentStatisticsMapper.java

@@ -0,0 +1,21 @@
+package com.sd.business.mapper.order;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.common.utils.wrapper.IWrapper;
+import com.sd.business.entity.order.po.OrderSalesShipmentStatistics;
+import com.sd.business.entity.order.vo.OrderSalesShipmentStatisticsVo;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 订单销售出库统计 Mapper 接口
+ * </p>
+ *
+ * @author
+ * @since 2023-10-20
+ */
+public interface OrderSalesShipmentStatisticsMapper extends BaseMapper<OrderSalesShipmentStatistics> {
+    List<OrderSalesShipmentStatisticsVo> getSalesShipmentStatisticsList(@Param("ew") IWrapper<OrderSalesShipmentStatistics> wrapper);
+}

+ 23 - 0
sd-business/src/main/java/com/sd/business/scheduled/OrderSalesShipmentStatisticsTask.java

@@ -0,0 +1,23 @@
+package com.sd.business.scheduled;
+
+import com.sd.business.service.order.OrderSalesShipmentStatisticsService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Profile;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+@Profile({"test", "prod"})
+@Component
+public class OrderSalesShipmentStatisticsTask {
+
+    @Autowired
+    private OrderSalesShipmentStatisticsService orderSalesShipmentStatisticsService;
+
+    /**
+     * 每天统计前一天的销售出库数量
+     */
+    @Scheduled(cron = "0 0 0 * * ?")
+    public void orderSalesShipmentStatistics() {
+        orderSalesShipmentStatisticsService.salesShipmentStatistics();
+    }
+}

+ 1 - 1
sd-business/src/main/java/com/sd/business/service/inventory/impl/InventoryServiceImpl.java

@@ -317,7 +317,7 @@ public class InventoryServiceImpl extends ServiceImpl<InventoryMapper, Inventory
 
                     inOutStorageDetails.setInUnitPrice(BigDecimal.ZERO);
                 } else {
-                    inventory.setQuantity(quantity);
+                    inventory.setQuantity(quantity.subtract(inventory.getLockQuantity()));
 
                     inOutStorageDetails.setInUnitPrice(inventory.getBalanceUnitPrice());
                 }

+ 40 - 0
sd-business/src/main/java/com/sd/business/service/order/OrderSalesShipmentStatisticsService.java

@@ -0,0 +1,40 @@
+package com.sd.business.service.order;
+
+import com.ruoyi.common.core.service.BaseService;
+import com.sd.business.entity.board.vo.TurnoverRateStatisticsVo;
+import com.sd.business.entity.order.po.OrderSalesShipmentStatistics;
+import com.sd.business.entity.order.vo.OrderSalesShipmentStatisticsVo;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * <p>
+ * 订单销售出库统计 服务类
+ * </p>
+ *
+ * @author
+ * @since 2023-10-20
+ */
+public interface OrderSalesShipmentStatisticsService extends BaseService<OrderSalesShipmentStatistics> {
+
+    /**
+     * 根据时间段获取销售出库数量统计
+     * @param beginDate
+     * @param endDate
+     * @return
+     */
+    List<OrderSalesShipmentStatisticsVo> getSalesShipmentStatisticsByDate(Date beginDate, Date endDate);
+
+    /**
+     * 获取周转率数据列表
+     *
+     * @return
+     */
+    List<TurnoverRateStatisticsVo> getTurnoverRateStatisticsList();
+
+    /**
+     * 销售出库统计任务
+     */
+    void salesShipmentStatistics();
+}

+ 151 - 0
sd-business/src/main/java/com/sd/business/service/order/impl/OrderSalesShipmentStatisticsServiceImpl.java

@@ -0,0 +1,151 @@
+package com.sd.business.service.order.impl;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.core.domain.BaseIdPo;
+import com.ruoyi.common.utils.wrapper.IWrapper;
+import com.sd.business.entity.board.vo.TurnoverRateStatisticsVo;
+import com.sd.business.entity.department.constant.DepartmentConstant;
+import com.sd.business.entity.inventory.po.InventoryBackup;
+import com.sd.business.entity.order.enums.OrderClassifyEnum;
+import com.sd.business.entity.order.enums.OrderStatusEnum;
+import com.sd.business.entity.order.po.OrderInfo;
+import com.sd.business.entity.order.po.OrderSalesShipmentStatistics;
+import com.sd.business.entity.order.po.OrderSku;
+import com.sd.business.entity.order.vo.OrderSalesShipmentStatisticsVo;
+import com.sd.business.entity.warehouse.constant.WarehouseConstant;
+import com.sd.business.mapper.order.OrderSalesShipmentStatisticsMapper;
+import com.sd.business.service.inventory.InventoryBackupService;
+import com.sd.business.service.order.OrderSalesShipmentStatisticsService;
+import com.sd.business.service.order.OrderService;
+import com.sd.business.service.order.OrderSkuService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 订单销售出库统计 服务实现类
+ * </p>
+ *
+ * @author
+ * @since 2023-10-20
+ */
+@Service
+public class OrderSalesShipmentStatisticsServiceImpl extends ServiceImpl<OrderSalesShipmentStatisticsMapper, OrderSalesShipmentStatistics> implements OrderSalesShipmentStatisticsService {
+
+    @Autowired
+    private OrderService orderService;
+
+    @Autowired
+    private OrderSkuService orderSkuService;
+
+    @Autowired
+    private InventoryBackupService inventoryBackupService;
+
+    @Override
+    public List<OrderSalesShipmentStatisticsVo> getSalesShipmentStatisticsByDate(Date beginDate, Date endDate) {
+        IWrapper<OrderSalesShipmentStatistics> wrapper = getWrapper();
+        wrapper.orderByDesc("osss", OrderSalesShipmentStatistics::getId);
+        wrapper.between("osss", OrderSalesShipmentStatistics::getTotalDate, beginDate, endDate);
+        wrapper.groupBy("osss.bom_spec_id");
+        return this.baseMapper.getSalesShipmentStatisticsList(wrapper);
+    }
+
+    @Override
+    public List<TurnoverRateStatisticsVo> getTurnoverRateStatisticsList() {
+        // 查询90天的周转率
+        Date date = new Date();
+        Date beginDate = DateUtil.beginOfDay(DateUtil.offsetDay(date, -90));
+        Date endDate = DateUtil.beginOfDay(DateUtil.offsetDay(date, -1));
+        List<OrderSalesShipmentStatisticsVo> statisticsVoList = this.getSalesShipmentStatisticsByDate(beginDate, date);
+        if (ObjectUtil.isEmpty(statisticsVoList)) {
+            return Collections.emptyList();
+        }
+        List<Long> bomSpecIds = statisticsVoList.stream().map(OrderSalesShipmentStatistics::getBomSpecId).collect(Collectors.toList());
+
+        // 期初库存数据
+        Map<Long, InventoryBackup> beginBackupMap = inventoryBackupService.mapKEntity(InventoryBackup::getBomSpecId, q -> q
+                .eq(InventoryBackup::getBackupDate, beginDate)
+                .eq(InventoryBackup::getDepartmentId, DepartmentConstant.SD_SPORTS)
+                .eq(InventoryBackup::getWarehouseId, WarehouseConstant.SEMI_FINISHED_PRODUCT)
+                .in(InventoryBackup::getBomSpecId, bomSpecIds));
+
+        // 期末库存数据
+        Map<Long, InventoryBackup> endBackupMap = inventoryBackupService.mapKEntity(InventoryBackup::getBomSpecId, q -> q
+                .eq(InventoryBackup::getBackupDate, endDate)
+                .eq(InventoryBackup::getDepartmentId, DepartmentConstant.SD_SPORTS)
+                .eq(InventoryBackup::getWarehouseId, WarehouseConstant.SEMI_FINISHED_PRODUCT)
+                .in(InventoryBackup::getBomSpecId, bomSpecIds));
+
+        List<TurnoverRateStatisticsVo> list = statisticsVoList.stream().map(item -> {
+            // 计算周转率
+            // 时间段库存周转天数 = 时间段天数 * (1 / 2) * (期初库存数量+期末库存数量) / 时间段销售量;
+            // 库存周转率 = 时间段天数 / 库存周转天数。
+            // 获取期初和期末数据
+            InventoryBackup beginBackup = beginBackupMap.get(item.getBomSpecId());
+            InventoryBackup endBackup = endBackupMap.get(item.getBomSpecId());
+            BigDecimal beginQuantity;
+            BigDecimal endQuantity;
+            if (beginBackup == null) {
+                beginQuantity = BigDecimal.ZERO;
+            } else {
+                beginQuantity = beginBackup.getQuantity().add(beginBackup.getLockQuantity() == null ? BigDecimal.ZERO : beginBackup.getLockQuantity());
+            }
+            if (endBackup == null) {
+                endQuantity = BigDecimal.ZERO;
+            } else {
+                endQuantity = endBackup.getQuantity().add(endBackup.getLockQuantity() == null ? BigDecimal.ZERO : endBackup.getLockQuantity());
+            }
+            BigDecimal days = new BigDecimal(90);
+            BigDecimal turnoverRate;
+            if (ObjectUtil.equals(item.getQuantity(), BigDecimal.ZERO)
+                    || ObjectUtil.equals(beginQuantity.add(endQuantity), BigDecimal.ZERO)) {
+                turnoverRate = BigDecimal.ZERO;
+            } else {
+                turnoverRate = days
+                        .divide(days.multiply(new BigDecimal("0.5"))
+                                        .multiply(beginQuantity.add(endQuantity))
+                                        .divide(item.getQuantity(), 4, RoundingMode.HALF_UP),
+                                4, RoundingMode.HALF_UP);
+            }
+            TurnoverRateStatisticsVo vo = new TurnoverRateStatisticsVo();
+            vo.setBomSpecCode(item.getBomSpecCode());
+            vo.setBomSpecName(item.getBomSpecName());
+            vo.setTurnoverRate(turnoverRate);
+            return vo;
+        }).collect(Collectors.toList());
+        return list;
+    }
+
+    @Override
+    public void salesShipmentStatistics() {
+        Date yesterday = DateUtil.yesterday();
+        String date = DateUtil.formatDate(yesterday);
+        List<OrderInfo> list = orderService.list(q -> q
+                .eq(OrderInfo::getStatus, OrderStatusEnum.COMPLETION_PRODUCTION.getKey())
+                .ne(OrderInfo::getClassify, OrderClassifyEnum.OUTSOURCE_ORDER.getKey())
+                .likeLeft(OrderInfo::getShippingTime, date)
+                .select(BaseIdPo::getId));
+        if (list.isEmpty()) {
+            return;
+        }
+        List<Long> orderIds = list.stream().map(BaseIdPo::getId).collect(Collectors.toList());
+        Map<Long, BigDecimal> map = orderSkuService.mapKV(OrderSku::getBomSpecId,
+                OrderSku::getQuantity,
+                q -> q.in(OrderSku::getOrderId, orderIds));
+        List<OrderSalesShipmentStatistics> statisticsDtoList = map.keySet().stream().map(item -> {
+            OrderSalesShipmentStatistics dto = new OrderSalesShipmentStatistics();
+            dto.setTotalDate(yesterday);
+            dto.setBomSpecId(item);
+            dto.setQuantity(map.get(item));
+            return dto;
+        }).collect(Collectors.toList());
+        this.saveBatch(statisticsDtoList);
+    }
+}

+ 12 - 15
sd-business/src/main/java/com/sd/business/service/production/impl/StockPreparationServiceImpl.java

@@ -230,29 +230,26 @@ public class StockPreparationServiceImpl implements StockPreparationService {
         }
 
         List<OrderInfo> orderInfoList = orderService.list(q -> q.in(BaseIdPo::getId, orderIdList));
-        List<OrderInfo> statementOrderList = new ArrayList<>();
-        for (OrderInfo orderInfo : orderInfoList) {
-            // 订单分类为无理由的订单,直接完成并生成对账单
-            if (ObjectUtil.equals(orderInfo.getClassify(), OrderClassifyEnum.NO_REASON_ORDER.getKey())) {
-                orderService.update(q -> q
-                        .eq(BaseIdPo::getId, orderInfo.getId())
-                        .set(OrderInfo::getStatus, OrderStatusEnum.COMPLETION_PRODUCTION.getKey()));
-                statementOrderList.add(orderInfo);
-            }
-        }
+        // 订单分类为无理由的订单,直接完成并生成对账单
+        List<OrderInfo> statementOrderList = orderInfoList.stream().filter(item -> ObjectUtil.equals(item.getClassify(), OrderClassifyEnum.NO_REASON_ORDER.getKey())).collect(Collectors.toList());
         // 生成对账单
-        if (!statementOrderList.isEmpty()) {
+        if (ObjectUtil.isNotEmpty(statementOrderList)) {
+            List<Long> orderIds = statementOrderList.stream().map(BaseIdPo::getId).collect(Collectors.toList());
+
+            orderService.update(q -> q
+                    .in(BaseIdPo::getId, orderIds)
+                    .set(OrderInfo::getStatus, OrderStatusEnum.COMPLETION_PRODUCTION.getKey())
+                    .set(OrderInfo::getShippingTime, new Date()));
+
             Map<Long, List<OrderInfo>> statementMap = statementOrderList.stream().collect(Collectors.groupingBy(OrderInfo::getDepartmentId));
             for (Long departmentId : statementMap.keySet()) {
-                List<Long> orderIds = statementMap.get(departmentId).stream().map(BaseIdPo::getId).collect(Collectors.toList());
+                List<Long> statementOrderIds = statementMap.get(departmentId).stream().map(BaseIdPo::getId).collect(Collectors.toList());
                 StatementOfAccountDto statement = new StatementOfAccountDto();
                 statement.setDepartmentId(departmentId);
-                statement.setOrderIdList(orderIds);
+                statement.setOrderIdList(statementOrderIds);
                 statementOfAccountService.add(statement);
             }
 
-            List<Long> orderIds = statementOrderList.stream().map(BaseIdPo::getId).collect(Collectors.toList());
-
             // 生产入库
             inventoryFinishedService.productionWarehousing(orderIds);
 

+ 16 - 0
sd-business/src/main/resources/mapper/order/OrderSalesShipmentStatisticsMapper.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.sd.business.mapper.order.OrderSalesShipmentStatisticsMapper">
+
+    <select id="getSalesShipmentStatisticsList" resultType="com.sd.business.entity.order.vo.OrderSalesShipmentStatisticsVo">
+        select
+            osss.bom_spec_id,
+            bs.code bomSpecCode,
+            bs.name bomSpecName,
+            sum(osss.quantity) quantity
+        from
+            order_sales_shipment_statistics osss
+            left join bom_spec bs on osss.bom_spec_id = bs.id
+        ${ew.customSqlSegment}
+    </select>
+</mapper>

+ 1 - 0
sd-wln/src/main/java/com/sd/wln/service/impl/WlnOrderServiceImpl.java

@@ -275,6 +275,7 @@ public class WlnOrderServiceImpl implements WlnOrderService {
                         orderInfo.setStatus(OrderStatusEnum.COMPLETION_PRODUCTION.getKey());
                     }
                     orderInfo.setClassify(OrderClassifyEnum.NO_REASON_ORDER.getKey());
+                    orderInfo.setShippingTime(new Date());
                     // 保存对账单列表
                     saveStatementOrderList.add(orderInfo);
                 }