Преглед изворни кода

订单新增成品备料出库

fgd пре 1 година
родитељ
комит
a237da0dad
16 измењених фајлова са 447 додато и 100 уклоњено
  1. 16 0
      sd-business/src/main/java/com/sd/business/controller/production/StockPreparationController.java
  2. 5 0
      sd-business/src/main/java/com/sd/business/entity/inventory/po/InventoryFinished.java
  3. 5 0
      sd-business/src/main/java/com/sd/business/entity/order/po/OrderInfo.java
  4. 4 0
      sd-business/src/main/java/com/sd/business/entity/production/dto/StockPreparationDto.java
  5. 47 0
      sd-business/src/main/java/com/sd/business/entity/production/vo/OutSkuVo.java
  6. 5 0
      sd-business/src/main/java/com/sd/business/entity/warehouse/constant/WarehouseConstant.java
  7. 2 9
      sd-business/src/main/java/com/sd/business/service/inventory/InventoryFinishedOrderService.java
  8. 19 2
      sd-business/src/main/java/com/sd/business/service/inventory/InventoryFinishedService.java
  9. 2 37
      sd-business/src/main/java/com/sd/business/service/inventory/impl/InventoryFinishedOrderServiceImpl.java
  10. 149 2
      sd-business/src/main/java/com/sd/business/service/inventory/impl/InventoryFinishedServiceImpl.java
  11. 2 9
      sd-business/src/main/java/com/sd/business/service/order/impl/OrderExchangeServiceImpl.java
  12. 40 34
      sd-business/src/main/java/com/sd/business/service/order/impl/OrderServiceImpl.java
  13. 13 0
      sd-business/src/main/java/com/sd/business/service/production/StockPreparationService.java
  14. 4 6
      sd-business/src/main/java/com/sd/business/service/production/impl/ProductionExceedReceiveServiceImpl.java
  15. 133 0
      sd-business/src/main/java/com/sd/business/service/production/impl/StockPreparationServiceImpl.java
  16. 1 1
      sd-wln/src/main/java/com/sd/wln/service/impl/WlnStatementOfAccountImpl.java

+ 16 - 0
sd-business/src/main/java/com/sd/business/controller/production/StockPreparationController.java

@@ -12,6 +12,7 @@ import org.springframework.web.bind.annotation.RestController;
 
 import javax.validation.Valid;
 import javax.validation.constraints.NotEmpty;
+import java.math.BigDecimal;
 import java.util.List;
 
 /**
@@ -72,4 +73,19 @@ public class StockPreparationController {
         return stockPreparationService.outBomList(dto);
     }
 
+    /**
+     * 待出库列表
+     */
+    @PostMapping("/outSkuList")
+    public List<OutSkuVo> outSkuList(@RequestBody StockPreparationDto dto) {
+        return stockPreparationService.outSkuList(dto);
+    }
+
+    /**
+     * 待备料列表主材总数
+     */
+    @PostMapping("/uncompletedListTotal")
+    public BigDecimal uncompletedListTotal(@RequestBody StockPreparationDto dto) {
+        return stockPreparationService.uncompletedListTotal(dto);
+    }
 }

+ 5 - 0
sd-business/src/main/java/com/sd/business/entity/inventory/po/InventoryFinished.java

@@ -32,4 +32,9 @@ public class InventoryFinished extends BasePo {
     @ExcelProperty(value = "数量", index = 2)
     private BigDecimal quantity;
 
+    /**
+     * 锁定数量
+     */
+    private BigDecimal lockQuantity;
+
 }

+ 5 - 0
sd-business/src/main/java/com/sd/business/entity/order/po/OrderInfo.java

@@ -302,4 +302,9 @@ public class OrderInfo extends BasePo {
      */
     private String deliveryCode;
 
+    /**
+     * 备料类型 0-半成品,1-成品
+     */
+    private Integer stockType;
+
 }

+ 4 - 0
sd-business/src/main/java/com/sd/business/entity/production/dto/StockPreparationDto.java

@@ -63,4 +63,8 @@ public class StockPreparationDto extends BaseSelectDto {
      */
     private String applicant;
 
+    /**
+     * 订单备料类型 0-半成品,1-成品
+     */
+    private Integer orderStockType;
 }

+ 47 - 0
sd-business/src/main/java/com/sd/business/entity/production/vo/OutSkuVo.java

@@ -0,0 +1,47 @@
+package com.sd.business.entity.production.vo;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+@Getter
+@Setter
+public class OutSkuVo {
+
+    /**
+     * sku规格id
+     */
+    private Long skuSpecId;
+
+    /**
+     * sku品号
+     */
+    private String skuSpecCode;
+
+    /**
+     * sku品名
+     */
+    private String skuSpecName;
+
+    /**
+     * 仓库id
+     */
+    private Long warehouseId;
+
+    /**
+     * 仓库名称
+     */
+    private String warehouseName;
+
+    /**
+     * 库存数量
+     */
+    private BigDecimal inventoryQuantity;
+
+    /**
+     * 出库数量
+     */
+    private BigDecimal outQuantity;
+
+}

+ 5 - 0
sd-business/src/main/java/com/sd/business/entity/warehouse/constant/WarehouseConstant.java

@@ -25,4 +25,9 @@ public interface WarehouseConstant {
      */
     Long PRODUCTION_DEFECTIVE = 1684037357424099330L;
 
+    /**
+     * 成品仓
+     */
+    Long FINISHED_PRODUCT = 1684037305712525313L;
+
 }

+ 2 - 9
sd-business/src/main/java/com/sd/business/service/inventory/InventoryFinishedOrderService.java

@@ -59,18 +59,11 @@ public interface InventoryFinishedOrderService extends BaseService<InventoryFini
     void erpExcelExport(List<InventoryFinishedErpImportDataDto> list);
 
     /**
-     * 订单售后入库
-     *
-     * @param orderSkuList 订单明细列表
-     */
-    void orderExchangeWarehousing(List<OrderSku> orderSkuList);
-
-    /**
      * 无源库存销售出库
      *
-     * @param orderIdList
+     * @param orderSkuList
      */
-    void noSourceSaleOutOfWarehouse(List<Long> orderIdList);
+    void noSourceSaleOutOfWarehouse(List<OrderSku> orderSkuList);
 
     /**
      * 根据订单id列表查询没有销货出库的订单

+ 19 - 2
sd-business/src/main/java/com/sd/business/service/inventory/InventoryFinishedService.java

@@ -5,6 +5,7 @@ import com.ruoyi.common.core.service.BaseService;
 import com.sd.business.entity.inventory.dto.InventoryFinishedSelectDto;
 import com.sd.business.entity.inventory.po.InventoryFinished;
 import com.sd.business.entity.inventory.vo.InventoryFinishedVo;
+import com.sd.business.entity.order.po.OrderSku;
 
 import java.util.List;
 
@@ -51,7 +52,23 @@ public interface InventoryFinishedService extends BaseService<InventoryFinished>
     void excelExport(InventoryFinishedSelectDto dto);
 
     /**
-     * 成品仓sku规格出入
+     * 锁定无源成品库
      */
-    void inOut(List<InventoryFinished> list, boolean isIn);
+    boolean lockNoSourceStorage(List<? extends OrderSku> orderSkuList);
+
+    /**
+     * 解锁无源成品库存
+     */
+    void unlockNoSourceStorage(List<OrderSku> orderSkuList);
+
+    /**
+     * 无源成品销售出库
+     * @param orderIdList
+     */
+    void noSourceSaleOutOfWarehouse(List<Long> orderIdList);
+
+    /**
+     * 无源成品入库
+     */
+    void noSourceInWarehousing(List<OrderSku> orderSkuList);
 }

+ 2 - 37
sd-business/src/main/java/com/sd/business/service/inventory/impl/InventoryFinishedOrderServiceImpl.java

@@ -291,50 +291,15 @@ public class InventoryFinishedOrderServiceImpl extends ServiceImpl<InventoryFini
     }
 
     @Override
-    public void orderExchangeWarehousing(List<OrderSku> orderSkuList) {
-        // 保存成品订单信息
-        List<InventoryFinishedOrder> list = orderSkuList.stream().map(item -> {
-            InventoryFinishedOrder inventoryFinishedOrder = new InventoryFinishedOrder();
-            inventoryFinishedOrder.setDepartmentId(DepartmentConstant.SD_SPORTS);
-            inventoryFinishedOrder.setSkuSpecId(item.getSkuSpecId());
-            inventoryFinishedOrder.setQuantity(item.getQuantity());
-            inventoryFinishedOrder.setStatus(StatusConstant.YES);
-            inventoryFinishedOrder.setExistingQuantity(item.getQuantity());
-            return inventoryFinishedOrder;
-        }).collect(Collectors.toList());
-        saveBatch(list);
-
-        // 添加流水记录
-        inventoryFinishedOrderDetailService.add(list, FinishedOperationTypeEnum.PRODUCTION_WAREHOUSING);
-    }
-
-    @Override
-    public void noSourceSaleOutOfWarehouse(List<Long> orderIdList) {
-        if (ObjectUtil.isEmpty(orderIdList)) {
+    public void noSourceSaleOutOfWarehouse(List<OrderSku> orderSkuList) {
+        if (ObjectUtil.isEmpty(orderSkuList)) {
             return;
         }
-        List<OrderSku> orderSkuList = orderSkuService.list(q -> q.in(OrderSku::getOrderId, orderIdList));
-        Map<Long, BigDecimal> orderSkuQuantityMap = orderSkuList.stream().collect(Collectors.toMap(OrderSku::getSkuSpecId, OrderSku::getQuantity, BigDecimal::add));
 
         // 获取所有无源可出库的库存
         Map<Long, List<InventoryFinishedOrder>> inventoryFinishedOrderMap = this.mapKGroup(InventoryFinishedOrder::getSkuSpecId, q -> q.eq(InventoryFinishedOrder::getStatus, 1)
                 .isNull(InventoryFinishedOrder::getOrderInfoId)
                 .orderByAsc(BaseIdPo::getId));
-        Map<Long, BigDecimal> map = inventoryFinishedOrderMap.values().stream()
-                .flatMap(Collection::stream)
-                .collect(Collectors.toMap(
-                        InventoryFinishedOrder::getSkuSpecId,
-                        InventoryFinishedOrder::getExistingQuantity,
-                        BigDecimal::add)
-                );
-
-        // 判断是否能出库
-        for (Map.Entry<Long, BigDecimal> entry : orderSkuQuantityMap.entrySet()) {
-            BigDecimal inventoryQuantity = map.getOrDefault(entry.getKey(), BigDecimal.ZERO);
-            if (entry.getValue().compareTo(inventoryQuantity) > 0) {
-                return;
-            }
-        }
 
         // 出库
         List<InventoryFinishedOrder> updateInventoryFinishedOrderList = new ArrayList<>();

+ 149 - 2
sd-business/src/main/java/com/sd/business/service/inventory/impl/InventoryFinishedServiceImpl.java

@@ -1,5 +1,6 @@
 package com.sd.business.service.inventory.impl;
 
+import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ruoyi.common.constant.StatusConstant;
@@ -136,8 +137,7 @@ public class InventoryFinishedServiceImpl extends ServiceImpl<InventoryFinishedM
     /**
      * 成品仓sku规格出入库
      */
-    @Override
-    public void inOut(List<InventoryFinished> list, boolean isIn) {
+    private void inOut(List<InventoryFinished> list, boolean isIn) {
 
         if (list.isEmpty()) {
             return;
@@ -169,8 +169,13 @@ public class InventoryFinishedServiceImpl extends ServiceImpl<InventoryFinishedM
                     quantity = inventoryFinished.getQuantity().add(item.getQuantity());
                 } else {
                     quantity = inventoryFinished.getQuantity().subtract(item.getQuantity());
+                    // 锁定数量更新
+                    if (item.getLockQuantity() != null) {
+                        inventoryFinished.setLockQuantity(inventoryFinished.getLockQuantity().subtract(item.getLockQuantity()));
+                    }
                 }
                 item.setId(inventoryFinished.getId());
+                item.setLockQuantity(inventoryFinished.getLockQuantity());
                 item.setQuantity(quantity);
             }
 
@@ -198,4 +203,146 @@ public class InventoryFinishedServiceImpl extends ServiceImpl<InventoryFinishedM
 
     }
 
+    /**
+     * 锁定无源成品库存
+     * @param orderSkuList
+     * @return
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public boolean lockNoSourceStorage(List<? extends OrderSku> orderSkuList) {
+        if (ObjectUtil.isEmpty(orderSkuList)) {
+            return true;
+        }
+
+        Map<Long, BigDecimal> map = orderSkuList.stream()
+                .collect(Collectors.toMap(OrderSku::getSkuSpecId, OrderSku::getQuantity, BigDecimal::add));
+
+        synchronized (this) {
+
+            List<InventoryFinished> list = list(q -> q.in(InventoryFinished::getSkuSpecId, map.keySet()));
+
+            if (map.size() != list.size()) {
+                return false;
+            }
+
+            // 查询无源成品数据
+            List<InventoryFinishedOrder> inventoryFinishedOrderList = inventoryFinishedOrderService.list(q -> q
+                    .in(InventoryFinishedOrder::getSkuSpecId, map.keySet())
+                    .eq(InventoryFinishedOrder::getStatus, 1)
+                    .isNull(InventoryFinishedOrder::getOrderInfoId));
+            Map<Long, BigDecimal> inventoryFinishedMap = inventoryFinishedOrderList.stream()
+                    .collect(Collectors.toMap(
+                            InventoryFinishedOrder::getSkuSpecId,
+                            InventoryFinishedOrder::getExistingQuantity,
+                            BigDecimal::add));
+
+            if (map.size() != inventoryFinishedMap.size()) {
+                return false;
+            }
+
+            for (InventoryFinished inventoryFinished : list) {
+                BigDecimal lockQuantity = map.get(inventoryFinished.getSkuSpecId());
+                // 查询成品sku现存数量,减去锁定库存,得出当前可用数量
+                BigDecimal existingQuantity = inventoryFinishedMap.getOrDefault(inventoryFinished.getSkuSpecId(), BigDecimal.ZERO);
+                if (existingQuantity.subtract(inventoryFinished.getLockQuantity()).compareTo(lockQuantity) >= 0) {
+                    inventoryFinished.setLockQuantity(inventoryFinished.getLockQuantity().add(lockQuantity));
+                } else {
+                    return false;
+                }
+            }
+
+            updateBatchById(list);
+        }
+
+        return true;
+    }
+
+    /**
+     * 解锁无源成品库存
+     * @param orderSkuList
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void unlockNoSourceStorage(List<OrderSku> orderSkuList) {
+        if (ObjectUtil.isEmpty(orderSkuList)) {
+            return;
+        }
+
+        Map<Long, BigDecimal> map = orderSkuList.stream()
+                .collect(Collectors.toMap(OrderSku::getSkuSpecId, OrderSku::getQuantity, BigDecimal::add));
+
+        synchronized (this) {
+
+            List<InventoryFinished> list = list(q -> q.in(InventoryFinished::getSkuSpecId, map.keySet()));
+
+            for (InventoryFinished inventoryFinished : list) {
+                BigDecimal lockQuantity = map.get(inventoryFinished.getSkuSpecId());
+                inventoryFinished.setLockQuantity(inventoryFinished.getLockQuantity().subtract(lockQuantity));
+            }
+
+            updateBatchById(list);
+        }
+    }
+
+    /**
+     * 无源成品销售出库
+     * @param orderIdList 订单id列表
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void noSourceSaleOutOfWarehouse(List<Long> orderIdList) {
+        if (ObjectUtil.isEmpty(orderIdList)) {
+            return;
+        }
+
+        // 查询订单sku明细
+        List<OrderSku> orderSkuList = orderSkuService.list(q -> q.in(OrderSku::getOrderId, orderIdList));
+        if (orderSkuList.isEmpty()) {
+            return;
+        }
+
+        // 成品库存出库
+        List<InventoryFinished> inventoryFinishedList = orderSkuList.stream().map(item -> {
+            InventoryFinished inventoryFinished = new InventoryFinished();
+            inventoryFinished.setQuantity(item.getQuantity());
+            inventoryFinished.setSkuSpecId(item.getSkuSpecId());
+            inventoryFinished.setLockQuantity(item.getQuantity());
+            return inventoryFinished;
+        }).collect(Collectors.toList());
+        inOut(inventoryFinishedList, false);
+
+        // 产品库订单出库
+        inventoryFinishedOrderService.noSourceSaleOutOfWarehouse(orderSkuList);
+    }
+
+    /**
+     * 无源退料入库
+     *
+     * @param orderSkuList
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void noSourceInWarehousing(List<OrderSku> orderSkuList) {
+        if (ObjectUtil.isEmpty(orderSkuList)) {
+            return;
+        }
+
+        // 添加成品仓库存
+        List<InventoryFinished> inventoryFinishedList = orderSkuList.stream().map(item -> {
+            InventoryFinished inventoryFinished = new InventoryFinished();
+            inventoryFinished.setSkuSpecId(item.getSkuSpecId());
+            inventoryFinished.setQuantity(item.getQuantity());
+            return inventoryFinished;
+        }).collect(Collectors.toList());
+        inOut(inventoryFinishedList, true);
+
+        // 清空来源信息
+        orderSkuList.forEach(item -> {
+            item.setId(null);
+            item.setOrderId(null);
+        });
+
+        inventoryFinishedOrderService.productionWarehousing(orderSkuList);
+    }
 }

+ 2 - 9
sd-business/src/main/java/com/sd/business/service/order/impl/OrderExchangeServiceImpl.java

@@ -304,15 +304,8 @@ public class OrderExchangeServiceImpl extends ServiceImpl<OrderExchangeMapper, O
             inOutStorageDto.setInOutStorageBomList(inOutStorageBomList);
             inOutStorageService.add(inOutStorageDto);
         } else {
-            // 生成无源成品信息,入成品库
-            List<InventoryFinished> inventoryFinishedList = orderSkuList.stream().map(item -> {
-                InventoryFinished inventoryFinished = new InventoryFinished();
-                inventoryFinished.setSkuSpecId(item.getSkuSpecId());
-                inventoryFinished.setQuantity(item.getQuantity());
-                return inventoryFinished;
-            }).collect(Collectors.toList());
-            inventoryFinishedService.inOut(inventoryFinishedList, true);
-            inventoryFinishedOrderService.orderExchangeWarehousing(orderSkuList);
+            // 入成品库
+            inventoryFinishedService.noSourceInWarehousing(orderSkuList);
         }
     }
 

+ 40 - 34
sd-business/src/main/java/com/sd/business/service/order/impl/OrderServiceImpl.java

@@ -32,7 +32,6 @@ import com.sd.business.entity.in.emums.InDetailTypeEnum;
 import com.sd.business.entity.in.emums.InOutTypeEnum;
 import com.sd.business.entity.in.emums.OutDetailTypeEnum;
 import com.sd.business.entity.in.po.InOutStorageBom;
-import com.sd.business.entity.inventory.po.Inventory;
 import com.sd.business.entity.order.dto.*;
 import com.sd.business.entity.order.enums.OrderClassifyEnum;
 import com.sd.business.entity.order.enums.OrderExceptionTypeEnum;
@@ -293,7 +292,13 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderInfo> implem
         List<OrderSkuDto> orderSkuList = orderDto.getOrderSkuList();
         if (ObjectUtil.equal(orderDto.getStatus(), OrderStatusEnum.STOCK_PREPARATION.getKey())
                 && ObjectUtil.notEqual(orderDto.getType(), 2)) {
-            lockStorage(orderSkuList);
+            // 先判断成品是否能锁定
+            if (inventoryFinishedService.lockNoSourceStorage(orderSkuList)) {
+                orderDto.setStockType(StatusConstant.YES);
+            } else {
+                lockStorage(orderSkuList);
+                orderDto.setStockType(StatusConstant.NO);
+            }
             orderDto.setLockStorage(StatusConstant.YES);
         } else {
             orderDto.setLockStorage(StatusConstant.NO);
@@ -549,7 +554,13 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderInfo> implem
         // 自主订单需要锁定库存
         List<OrderSkuDto> orderSkuList = dto.getOrderSkuList();
         if (Objects.equals(dto.getType(), 1)) {
-            lockStorage(orderSkuList);
+            // 先判断成品是否能锁定
+            if (inventoryFinishedService.lockNoSourceStorage(orderSkuList)) {
+                dto.setStockType(StatusConstant.YES);
+            } else {
+                lockStorage(orderSkuList);
+                dto.setStockType(StatusConstant.NO);
+            }
             dto.setLockStorage(StatusConstant.YES);
         }
 
@@ -842,10 +853,17 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderInfo> implem
 
         if (ObjectUtil.equal(orderInfo.getStatus(), OrderStatusEnum.STOCK_PREPARATION.getKey())) {
             List<OrderSku> list = orderSkuService.list(q -> q.eq(OrderSku::getOrderId, orderInfo.getId()));
-            lockStorage(list);
+            // 先判断成品是否能锁定
+            if (inventoryFinishedService.lockNoSourceStorage(list)) {
+                orderInfo.setStockType(StatusConstant.YES);
+            } else {
+                lockStorage(list);
+                orderInfo.setStockType(StatusConstant.NO);
+            }
             update(q -> q
                     .eq(BaseIdPo::getId, orderInfo.getId())
-                    .set(OrderInfo::getLockStorage, StatusConstant.YES));
+                    .set(OrderInfo::getLockStorage, StatusConstant.YES)
+                    .set(OrderInfo::getStockType, orderInfo.getStockType()));
         }
 
         update(q -> q
@@ -887,6 +905,18 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderInfo> implem
         List<OrderSku> orderSkuList = orderSkuService.list(q -> q.eq(OrderSku::getOrderId, id));
         List<OrderSkuBom> orderSkuBomList = orderSkuBomService.list(q -> q.eq(OrderSkuBom::getOrderId, id));
 
+        // 成品退料
+        if (Objects.equals(orderInfo.getStockType(), StatusConstant.YES)) {
+            inventoryFinishedService.noSourceInWarehousing(orderSkuList);
+            delete(id);
+            OrderOperatingLog orderOperatingLog = new OrderOperatingLog();
+            orderOperatingLog.setType(30);
+            orderOperatingLog.setOrderId(id);
+            orderOperatingLog.setOrderCode(orderInfo.getCode());
+            orderOperatingLogService.save(orderOperatingLog);
+            return;
+        }
+
         Map<Long, OrderSku> orderSkuMap = orderSkuList.stream().collect(Collectors.toMap(BaseIdPo::getId, Function.identity()));
 
         // 合并主材和包材
@@ -1416,34 +1446,6 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderInfo> implem
         ObsFileUtil.removeFile(id);
     }
 
-    private void checkSkuInventory(List<OrderSkuDto> orderSkuList) {
-        List<Long> bomSpecIdList = orderSkuList.stream().map(OrderSku::getBomSpecId).collect(Collectors.toList());
-        // 区分半成品仓和包材仓库
-        Map<Long, BomSpecBo> bomSpecBoMap = skuSpecService.getBomSpecBoByIdList(bomSpecIdList);
-        // 自建订单判断库存
-        for (OrderSkuDto orderSkuDto : orderSkuList) {
-            // 判断sku库存
-            Long bomSpecId = orderSkuDto.getBomSpecId();
-            BomSpecBo bomSpecBo = bomSpecBoMap.get(bomSpecId);
-            if (bomSpecBo == null) {
-                throw new ServiceException("未知bom规格id:" + bomSpecId);
-            }
-            Long warehouseId;
-            // 主材
-            if (ObjectUtil.equals(bomSpecBo.getClassifyParentId(), 1L)) {
-                warehouseId = WarehouseConstant.SEMI_FINISHED_PRODUCT;
-            } else {
-                warehouseId = WarehouseConstant.PACKAGING_MATERIAL;
-            }
-            Inventory inventory = inventoryService.getOne(q -> q.eq(Inventory::getWarehouseId, warehouseId)
-                    .eq(Inventory::getBomSpecId, bomSpecId));
-            if (inventory == null || inventory.getQuantity().compareTo(orderSkuDto.getQuantity()) < 0) {
-                throw new ServiceException("操作失败,品名为:" + bomSpecBo.getBomSpecName() + " 的bom库存不足,库存为:" +
-                        (inventory == null ? BigDecimal.ZERO : inventory.getQuantity()));
-            }
-        }
-    }
-
     /**
      * 锁定库存
      */
@@ -1483,7 +1485,11 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderInfo> implem
                 .filter(item -> bomSpecBoMap.get(item.getBomSpecId()).getClassifyParentId().equals(1L))
                 .collect(Collectors.toList());
 
-        inventoryService.unlockStorage(orderSkuList);
+        if (Objects.equals(orderInfo.getStockType(), 1)) {
+            inventoryFinishedService.unlockNoSourceStorage(orderSkuList);
+        } else {
+            inventoryService.unlockStorage(orderSkuList);
+        }
     }
 
     private void sendMq(OrderInfoDto dto) {

+ 13 - 0
sd-business/src/main/java/com/sd/business/service/production/StockPreparationService.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.sd.business.entity.production.dto.StockPreparationDto;
 import com.sd.business.entity.production.vo.*;
 
+import java.math.BigDecimal;
 import java.util.List;
 
 public interface StockPreparationService {
@@ -40,4 +41,16 @@ public interface StockPreparationService {
      */
     List<OutBomVo> outBomList(StockPreparationDto dto);
 
+    /**
+     * 成品备料待出库列表
+     */
+    List<OutSkuVo> outSkuList(StockPreparationDto dto);
+
+    /**
+     * 待备料列表主材总数
+     *
+     * @param dto
+     * @return
+     */
+    BigDecimal uncompletedListTotal(StockPreparationDto dto);
 }

+ 4 - 6
sd-business/src/main/java/com/sd/business/service/production/impl/ProductionExceedReceiveServiceImpl.java

@@ -287,9 +287,8 @@ public class ProductionExceedReceiveServiceImpl extends ServiceImpl<ProductionEx
                 orderSku.setQuantity(item.getQuantity());
                 return orderSku;
             }).collect(Collectors.toList());
-            // 成品入库,并生成明细
-            inventoryFinishedService.inOut(inventoryFinishedList, true);
-            inventoryFinishedOrderService.productionWarehousing(orderSkuList);
+            // 无源成品入库,并生成明细
+            inventoryFinishedService.noSourceInWarehousing(orderSkuList);
         }
 
         // 保存超领数据
@@ -399,9 +398,8 @@ public class ProductionExceedReceiveServiceImpl extends ServiceImpl<ProductionEx
                     orderSku.setQuantity(item.getQuantity());
                     return orderSku;
                 }).collect(Collectors.toList());
-                // 成品入库,并生成明细
-                inventoryFinishedService.inOut(inventoryFinishedList, true);
-                inventoryFinishedOrderService.productionWarehousing(orderSkuList);
+                // 无源成品入库,并生成明细
+                inventoryFinishedService.noSourceInWarehousing(orderSkuList);
             }
         }
 

+ 133 - 0
sd-business/src/main/java/com/sd/business/service/production/impl/StockPreparationServiceImpl.java

@@ -15,6 +15,7 @@ import com.sd.business.entity.in.emums.InOutTypeEnum;
 import com.sd.business.entity.in.emums.OutDetailTypeEnum;
 import com.sd.business.entity.in.po.InOutStorageBom;
 import com.sd.business.entity.inventory.po.Inventory;
+import com.sd.business.entity.inventory.po.InventoryFinishedOrder;
 import com.sd.business.entity.order.enums.OrderClassifyEnum;
 import com.sd.business.entity.order.enums.OrderExceptionTypeEnum;
 import com.sd.business.entity.order.enums.OrderStatusEnum;
@@ -33,6 +34,7 @@ import com.sd.business.service.bom.BomClassifyService;
 import com.sd.business.service.bom.BomService;
 import com.sd.business.service.bom.BomSpecService;
 import com.sd.business.service.in.InOutStorageService;
+import com.sd.business.service.inventory.InventoryFinishedOrderService;
 import com.sd.business.service.inventory.InventoryFinishedService;
 import com.sd.business.service.inventory.InventoryService;
 import com.sd.business.service.order.OrderPackageBomService;
@@ -100,6 +102,9 @@ public class StockPreparationServiceImpl implements StockPreparationService {
     @Autowired
     private OrderPackageBomService orderPackageBomService;
 
+    @Autowired
+    private InventoryFinishedOrderService inventoryFinishedOrderService;
+
     @Override
     public List<UncompletedVo> uncompletedList(StockPreparationDto dto) {
 
@@ -308,6 +313,12 @@ public class StockPreparationServiceImpl implements StockPreparationService {
                 .set(OrderSku::getStockPreparationTime, stockPreparationTime)
                 .set(OrderSku::getStockPreparationStatus, StatusConstant.YES));
 
+        // 成品库出库
+        if (Objects.equals(dto.getOrderStockType(), 1)) {
+            orderFinishedDelivery(list);
+            return;
+        }
+
         // 订单出库
         orderDelivery(list, dto);
 
@@ -361,6 +372,39 @@ public class StockPreparationServiceImpl implements StockPreparationService {
 
     }
 
+    private void orderFinishedDelivery(List<StockPreparationVo> list) {
+        // 成品出库
+        List<Long> orderIdList = list.stream().map(StockPreparationVo::getOrderId).distinct().collect(Collectors.toList());
+        inventoryFinishedService.noSourceSaleOutOfWarehouse(orderIdList);
+
+        // 生产工单
+        List<ProductionWorkOrder> productionWorkOrderList = new ArrayList<>();
+        Map<Long, List<StockPreparationVo>> map = list.stream().collect(Collectors.groupingBy(StockPreparationVo::getOrderId));
+        Map<Long, List<OrderSku>> orderSkuMap = orderSkuService.list(q -> q.in(OrderSku::getOrderId, orderIdList))
+                .stream().collect(Collectors.groupingBy(OrderSku::getOrderId));
+        map.forEach((orderId, stockPreparationVoList) -> {
+            StockPreparationVo stockPreparationVo = stockPreparationVoList.get(0);
+            String orderCode = stockPreparationVo.getOrderCode();
+            String orderWlnCode = stockPreparationVo.getOrderWlnCode();
+            addWorkOrder(orderId, ObjectUtil.defaultIfNull(orderWlnCode, orderCode),
+                    orderSkuMap.getOrDefault(orderId, Collections.emptyList()), productionWorkOrderList);
+        });
+
+        skuSpecService.attributeAssign(productionWorkOrderList, ProductionWorkOrder::getSkuSpecId,
+                (item, skuSpec) -> item.setMachinedPanel(skuSpec.getMachinedPanel()));
+
+        // 直接完成生产任务
+        productionWorkOrderList.forEach(item -> {
+            item.setStatus(3);
+            item.setCompleteTime(new Date());
+        });
+
+        orderService.update(q -> q
+                .in(BaseIdPo::getId, orderIdList)
+                .set(OrderInfo::getStatus, OrderStatusEnum.COMPLETION_PRODUCTION.getKey()));
+        productionWorkOrderService.saveBatch(productionWorkOrderList);
+    }
+
     @Override
     public List<PackageBomVo> getPackageBomList(List<Long> orderSkuIdList) {
 
@@ -398,6 +442,7 @@ public class StockPreparationServiceImpl implements StockPreparationService {
     public List<OutBomVo> outBomList(StockPreparationDto dto) {
         Long outDepartmentId = dto.getOutDepartmentId();
         Assert.notNull(outDepartmentId, "出库事业部id不能为空");
+        dto.setOrderStockType(0);
 
         // 订单sku列表
         IWrapper<StockPreparationVo> wrapper = getWrapper(dto);
@@ -530,6 +575,92 @@ public class StockPreparationServiceImpl implements StockPreparationService {
 
     }
 
+    @Override
+    public List<OutSkuVo> outSkuList(StockPreparationDto dto) {
+        Long outDepartmentId = dto.getOutDepartmentId();
+        Assert.notNull(outDepartmentId, "出库事业部id不能为空");
+        dto.setOrderStockType(1);
+
+        // 订单sku列表
+        IWrapper<StockPreparationVo> wrapper = getWrapper(dto);
+        List<StockPreparationVo> stockPreparationVoList = stockPreparationMapper.uncompletedList(wrapper);
+
+        if (stockPreparationVoList.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        List<Long> orderIdList = stockPreparationVoList.stream().map(StockPreparationVo::getOrderId).distinct().collect(Collectors.toList());
+        List<OrderSku> orderSkuList = orderSkuService.list(q -> q.in(OrderSku::getOrderId, orderIdList));
+
+        Map<Long, OutSkuVo> map = orderSkuList.stream()
+                .map(item -> {
+                    OutSkuVo outSkuVo = new OutSkuVo();
+                    outSkuVo.setSkuSpecId(item.getSkuSpecId());
+                    outSkuVo.setOutQuantity(item.getQuantity());
+                    return outSkuVo;
+                })
+                .collect(Collectors.toMap(
+                        OutSkuVo::getSkuSpecId,
+                        Function.identity(),
+                        (v1, v2) -> {
+                            v1.setOutQuantity(v1.getOutQuantity().add(v2.getOutQuantity()));
+                            return v1;
+                        })
+                );
+
+        List<OutSkuVo> outBomVoList = new ArrayList<>(map.values());
+
+        Map<Long, SkuSpec> skuSpecMap = skuSpecService.byIdsToMap(map.keySet());
+        // 查询成品库存
+        List<InventoryFinishedOrder> list = inventoryFinishedOrderService.list(
+                q -> q.in(InventoryFinishedOrder::getSkuSpecId, map.keySet())
+                        .eq(InventoryFinishedOrder::getStatus, 1)
+                        .isNull(InventoryFinishedOrder::getOrderInfoId));
+        Map<Long, BigDecimal> inventoryMap = list.stream()
+                .collect(Collectors.toMap(
+                        InventoryFinishedOrder::getSkuSpecId,
+                        InventoryFinishedOrder::getExistingQuantity,
+                        BigDecimal::add)
+                );
+
+        // 赋值
+        for (OutSkuVo outSkuVo : outBomVoList) {
+            Long skuSpecId = outSkuVo.getSkuSpecId();
+            SkuSpec skuSpec = skuSpecMap.get(skuSpecId);
+            outSkuVo.setSkuSpecCode(skuSpec.getCode());
+            outSkuVo.setSkuSpecName(skuSpec.getName());
+            outSkuVo.setWarehouseId(WarehouseConstant.FINISHED_PRODUCT);
+            outSkuVo.setWarehouseName("成品仓");
+            outSkuVo.setInventoryQuantity(inventoryMap.getOrDefault(skuSpecId, BigDecimal.ZERO));
+        }
+
+        return outBomVoList;
+    }
+
+    @Override
+    public BigDecimal uncompletedListTotal(StockPreparationDto dto) {
+        IWrapper<StockPreparationVo> wrapper = IWrapper.getWrapper();
+        wrapper.eq("oi", OrderInfo::getStatus, OrderStatusEnum.STOCK_PREPARATION.getKey());
+        wrapper.eq("oi", OrderInfo::getExceptionType, OrderExceptionTypeEnum.NORMAL.getKey().toString());
+        wrapper.eq("os", OrderSku::getStockPreparationStatus, StatusConstant.NO);
+        wrapper.and(q -> q
+                .ge("oi", OrderInfo::getWlnStatus, 2)
+                .or().eq("oi", OrderInfo::getSource, 1));
+        wrapper.and(q -> q
+                .and(r -> r.isNull("oi.flow_id").isNull("oi.flow_status"))
+                .or(r -> r.eq("oi", OrderInfo::getFlowStatus, FlowStatusEnum.PASS.getKey())));
+        wrapper.eq("oi", OrderInfo::getStockType, dto.getOrderStockType());
+        // 不计算委外订单主材数量
+        wrapper.ne("oi", OrderInfo::getType, 2);
+        List<StockPreparationVo> stockPreparationVoList = stockPreparationMapper.uncompletedList(wrapper);
+
+        if (ObjectUtil.isEmpty(stockPreparationVoList)) {
+            return BigDecimal.ZERO;
+        }
+
+        return stockPreparationVoList.stream().map(StockPreparationVo::getQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
+    }
+
     /**
      * 获取wrapper
      */
@@ -551,6 +682,8 @@ public class StockPreparationServiceImpl implements StockPreparationService {
                 .and(r -> r.isNull("oi.flow_id").isNull("oi.flow_status"))
                 .or(r -> r.eq("oi", OrderInfo::getFlowStatus, FlowStatusEnum.PASS.getKey())));
 
+        wrapper.eq("oi", OrderInfo::getStockType, dto.getOrderStockType());
+
         return wrapper;
     }
 

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

@@ -56,7 +56,7 @@ public class WlnStatementOfAccountImpl implements WlnStatementOfAccount {
 
         // 获取没绑定对账单的订单
         List<OrderInfo> orderList = orderService.list(q -> q
-                .ge(OrderInfo::getStatus, OrderStatusEnum.IN_PRODUCTION.getKey())
+                .in(OrderInfo::getStatus, OrderStatusEnum.IN_PRODUCTION.getKey(), OrderStatusEnum.COMPLETION_PRODUCTION.getKey())
                 .isNotNull(OrderInfo::getWlnCode)
                 .isNull(OrderInfo::getStatementOfAccountId));
         if (orderList.isEmpty()) {