Browse Source

1.搅拌槽对接需求

ChenYang 1 year ago
parent
commit
6fb6d6e3f3
23 changed files with 711 additions and 94 deletions
  1. 5 0
      base_sql/bucket_sql/xuankuang_ddl_20230904.sql
  2. 27 9
      ruoyi-admin/src/main/java/com/ruoyi/init/StartService.java
  3. 13 0
      ruoyi-admin/src/main/java/com/ruoyi/xuankuang/controller/test/UnpackingMachineController.java
  4. 5 0
      ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
  5. 27 20
      warewms-ams/src/main/java/com/ruoyi/ams/order/domain/WmsDocOrderDetails.java
  6. 4 4
      warewms-ams/src/main/java/com/ruoyi/ams/order/mapper/WmsDocOrderDetailsMapper.java
  7. 29 4
      warewms-ams/src/main/java/com/ruoyi/ams/order/service/IWmsDocOrderDetailsService.java
  8. 8 4
      warewms-ams/src/main/java/com/ruoyi/ams/order/service/IWmsDocOrderHeaderService.java
  9. 28 2
      warewms-ams/src/main/java/com/ruoyi/ams/order/service/impl/WmsDocOrderDetailsServiceImpl.java
  10. 16 5
      warewms-ams/src/main/java/com/ruoyi/ams/order/service/impl/WmsDocOrderHeaderServiceImpl.java
  11. 6 2
      warewms-ams/src/main/java/com/ruoyi/ams/task/service/impl/WcsTaskServiceImpl.java
  12. 71 0
      warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/domain/dto/SkuAgitatedTankAttrDTO.java
  13. 15 1
      warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/facade/impl/UnpackingMachineFacadeImpl.java
  14. 3 3
      warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/service/AgvCallProxyService.java
  15. 18 0
      warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/service/IAgitatedTankService.java
  16. 98 5
      warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/service/StirringTankClientService.java
  17. 10 2
      warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/service/WcsTaskSubService.java
  18. 67 25
      warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/service/WmsDocOrderSubService.java
  19. 102 0
      warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/service/impl/AgitatedTankServiceImpl.java
  20. 11 2
      warewms-hard/src/main/java/com/ruoyi/hard/xuankang/ConvertUtil.java
  21. 94 6
      warewms-hard/src/main/java/com/ruoyi/hard/xuankang/StirringTankClient.java
  22. 50 0
      warewms-hard/src/main/java/com/ruoyi/hard/xuankang/UnpackingMachineClient.java
  23. 4 0
      warewms-hard/src/main/java/com/ruoyi/hard/xuankang/UnpackingMachineSubClient.java

+ 5 - 0
base_sql/bucket_sql/xuankuang_ddl_20230904.sql

@@ -279,3 +279,8 @@ INSERT INTO `ams_hexdefine_detail` (`business_type`, `col_name`, `col_type`, `bi
 INSERT INTO `ams_hexdefine_detail` (`business_type`, `col_name`, `col_type`, `bind_table`, `col_val`, `val_type`, `sort_index`) VALUES ( '101', 'IKEY', '2', NULL, 'iKey', '1', '10');
 INSERT INTO `ams_hexdefine_detail` (`business_type`, `col_name`, `col_type`, `bind_table`, `col_val`, `val_type`, `sort_index`) VALUES ( '101', 'LP0', '2', NULL, 'ext2', '1', '11');
 INSERT INTO `ams_hexdefine_detail` (`business_type`, `col_name`, `col_type`, `bind_table`, `col_val`, `val_type`, `sort_index`) VALUES ( '101', 'LP1', '2', NULL, 'ext3', '1', '12');
+
+
+
+INSERT INTO `sys_job` (`job_id`, `job_name`, `job_group`, `invoke_target`, `cron_expression`, `misfire_policy`, `concurrent`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (18, '搅拌槽出库单创建流程', 'DEFAULT', 'startService.agitateTankCreateOrderTask', '0/30 * * * * ?', '1', '1', '0', 'admin', '2023-09-22 13:54:21', 'admin', '2023-09-22 13:54:31', NULL);
+INSERT INTO `sys_job` (`job_id`, `job_name`, `job_group`, `invoke_target`, `cron_expression`, `misfire_policy`, `concurrent`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (19, '搅拌槽开始任务流程', 'DEFAULT', 'startService.agitateTankExcuteTask', '0/30 * * * * ?', '1', '1', '0', 'admin', '2023-09-22 13:54:21', 'admin', '2023-09-22 13:54:31', NULL);

+ 27 - 9
ruoyi-admin/src/main/java/com/ruoyi/init/StartService.java

@@ -3,12 +3,10 @@ package com.ruoyi.init;
 import com.ruoyi.ams.agv.ndc.AciService;
 import com.ruoyi.ams.agv.ndc.config.InitTaskConfig;
 import com.ruoyi.ams.agv.ndc.thread.AciServiceThread;
-import com.ruoyi.ams.agv.ndc.thread.AutoButtonBoxTask;
 import com.ruoyi.ams.agv.ndc.thread.AutoTaskThread;
-import com.ruoyi.ams.agv.ndc.thread.AutoTranSitTask;
 import com.ruoyi.ams.business.IBusinessService;
+import com.ruoyi.ams.xuankuang.service.IAgitatedTankService;
 import com.ruoyi.ams.xuankuang.service.StirringTankClientService;
-import com.ruoyi.base.service.IBaseLocationInfoService;
 import com.ruoyi.hard.xuankang.StirringTankClient;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -16,6 +14,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.boot.CommandLineRunner;
 import org.springframework.stereotype.Component;
 
+import java.util.List;
 import java.util.concurrent.ScheduledExecutorService;
 
 @Slf4j
@@ -29,12 +28,6 @@ public class StartService implements CommandLineRunner {
     @Autowired
     private AciService aciService;
     @Autowired
-    private AutoTranSitTask autoTranSitTask;
-    @Autowired
-    private AutoButtonBoxTask autoButtonBoxTask;
-    @Autowired
-    private IBaseLocationInfoService baseLocationInfoService;
-    @Autowired
     private StirringTankClient stirringTankClient;
     @Autowired
     private StirringTankClientService stirringTankClientService;
@@ -43,6 +36,10 @@ public class StartService implements CommandLineRunner {
     @Qualifier("scheduledExecutorService")
     private ScheduledExecutorService scheduledExecutorService;
 
+
+    @Autowired
+    private IAgitatedTankService agitatedTankService;
+
     @Override
     public void run(String... args) throws Exception {
         //自动下发任务
@@ -60,6 +57,25 @@ public class StartService implements CommandLineRunner {
             Thread thread = new Thread(new AciServiceThread(aciService));
             thread.start();
         }
+
+        /*scheduledExecutorService.scheduleAtFixedRate(
+            ()-> agitateTankCreateOrderTask(), 1, 1, TimeUnit.SECONDS
+        );
+
+
+        scheduledExecutorService.scheduleAtFixedRate(
+                ()-> agitateTankExcuteTask(), 1, 1, TimeUnit.SECONDS
+        );*/
+    }
+
+    public void agitateTankExcuteTask() {
+        List<String> skuList = StirringTankClientService.getSkuList();
+        skuList.forEach(item -> agitatedTankService.agitateTankExcuteTask(item));
+    }
+
+    public void agitateTankCreateOrderTask() {
+        List<String> skuList = StirringTankClientService.getSkuList();
+        skuList.forEach(item -> agitatedTankService.agitateTankCreateOrderTask(item));
     }
 
     /**
@@ -83,6 +99,8 @@ public class StartService implements CommandLineRunner {
         stirringTankClientService.clear();
     }
 
+
+
     /**
      * 循环触发碳酸钠出库流程
      */

+ 13 - 0
ruoyi-admin/src/main/java/com/ruoyi/xuankuang/controller/test/UnpackingMachineController.java

@@ -1,11 +1,14 @@
 package com.ruoyi.xuankuang.controller.test;
 
+import cn.hutool.core.util.BooleanUtil;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.hard.xuankang.ConvertUtil;
 import com.ruoyi.hard.xuankang.UnpackingMachineClient;
 import com.ruoyi.hard.xuankang.UnpackingMachineSubClient;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ArrayUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -20,6 +23,7 @@ import org.springframework.web.bind.annotation.RestController;
 @Api("拆包机接口测试")
 @RestController
 @RequestMapping("/test/wcs2")
+@Slf4j
 public class UnpackingMachineController {
     @Autowired
     private UnpackingMachineClient unpackingMachineClient;
@@ -37,6 +41,15 @@ public class UnpackingMachineController {
         return unpackingMachineClient.readUnpacking01();
     }
 
+
+    @ApiOperation("读拆包机上下割刀运行状态接口")
+    @GetMapping("/readCutOffToolStatus")
+    public Boolean[] readCutOffToolStatus(String lineId) {
+        Boolean[] cutOffToolStatus = unpackingMachineClient.readCutOffToolStatus(lineId);
+        log.info("current status is {}", BooleanUtil.and(ArrayUtils.toPrimitive(cutOffToolStatus)));
+        return unpackingMachineClient.readCutOffToolStatus(lineId);
+    }
+
     /**
      * 读拆包机3# 4#各部件状态
      *

+ 5 - 0
ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java

@@ -254,6 +254,11 @@ public class Constants
     public static final String OUTPUT = "output";
 
 
+
+    public static final String AGITATED_TANK = "agitatedTank";
+    public static final String NORMAL = "normal";
+
+
     private static final Integer FIRST_FLOOR = 1;
 
     private static final Integer SECOND_FLOOR = 2;

+ 27 - 20
warewms-ams/src/main/java/com/ruoyi/ams/order/domain/WmsDocOrderDetails.java

@@ -1,10 +1,12 @@
 package com.ruoyi.ams.order.domain;
 
-import java.math.BigDecimal;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.core.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.math.BigDecimal;
 
 /**
  * 出库单对象 wms_doc_order_details
@@ -18,6 +20,7 @@ public class WmsDocOrderDetails extends BaseEntity
 
 
     /** 物料类型 */
+    @TableField(exist = false)
     private int desc2;
 
 
@@ -202,82 +205,86 @@ public class WmsDocOrderDetails extends BaseEntity
 
     /**  */
     //@Excel(name = "")
+    @TableField(exist = false)
     private String dEdi01;
 
     /** 目标库位 */
     //@Excel(name = "目标库位")
+    @TableField(exist = false)
     private String dEdi02;
 
     /**  */
     //@Excel(name = "")
+    @TableField(exist = false)
     private String dEdi03;
 
-    /**  */
+
     //@Excel(name = "")
+    @TableField(exist = false)
     private String dEdi04;
 
     /**  */
-    //@Excel(name = "")
+    @TableField(exist = false)
     private String dEdi05;
 
     /**  */
-    //@Excel(name = "")
+    @TableField(exist = false)
     private String dEdi06;
 
     /**  */
-    //@Excel(name = "")
+    @TableField(exist = false)
     private String dEdi07;
 
     /**  */
-    //@Excel(name = "")
+    @TableField(exist = false)
     private String dEdi08;
 
     /**  */
-    //@Excel(name = "")
+    @TableField(exist = false)
     private BigDecimal dEdi09;
 
     /**  */
-    //@Excel(name = "")
+    @TableField(exist = false)
     private BigDecimal dEdi10;
 
     /**  */
-    //@Excel(name = "")
+    @TableField(exist = false)
     private String dEdi11;
 
     /**  */
-    //@Excel(name = "")
+    @TableField(exist = false)
     private String dEdi12;
 
     /**  */
-    //@Excel(name = "")
+    @TableField(exist = false)
     private String dEdi13;
 
     /**  */
-    //@Excel(name = "")
+    @TableField(exist = false)
     private String dEdi14;
 
     /**  */
-    //@Excel(name = "")
+    @TableField(exist = false)
     private String dEdi15;
 
     /**  */
-    //@Excel(name = "")
+    @TableField(exist = false)
     private String dEdi16;
 
     /**  */
-    //@Excel(name = "")
+    @TableField(exist = false)
     private String dEdi17;
 
     /**  */
-    //@Excel(name = "")
+    @TableField(exist = false)
     private String dEdi18;
 
     /**  */
-    //@Excel(name = "")
+    @TableField(exist = false)
     private String dEdi19;
 
     /**  */
-    //@Excel(name = "")
+    @TableField(exist = false)
     private String dEdi20;
 
     /** 跟踪号(未启用) */

+ 4 - 4
warewms-ams/src/main/java/com/ruoyi/ams/order/mapper/WmsDocOrderDetailsMapper.java

@@ -1,18 +1,19 @@
 package com.ruoyi.ams.order.mapper;
 
-import java.util.List;
-
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.ruoyi.ams.order.domain.WmsDocOrderDetails;
 import com.ruoyi.ams.order.vo.StockOrderVO;
 import org.apache.ibatis.annotations.Param;
 
+import java.util.List;
+
 /**
  * 出库单Mapper接口
  *
  * @author ruoyi
  * @date 2022-10-28
  */
-public interface WmsDocOrderDetailsMapper {
+public interface WmsDocOrderDetailsMapper extends BaseMapper<WmsDocOrderDetails> {
     /**
      * 查询出库单
      *
@@ -92,7 +93,6 @@ public interface WmsDocOrderDetailsMapper {
     /**
      * 删除出库单明细
      * @param orderNo
-     * @param orderLoneNo
      * @return
      */
     int deleteWmsDocAsnDetailsByOrderNoLineNo(@Param("orderNo") String orderNo, @Param("orderLineNo") Long orderLineNo);

+ 29 - 4
warewms-ams/src/main/java/com/ruoyi/ams/order/service/IWmsDocOrderDetailsService.java

@@ -1,12 +1,11 @@
 package com.ruoyi.ams.order.service;
 
+import com.ruoyi.ams.order.domain.WmsDocOrderDetails;
+
 import java.math.BigDecimal;
 import java.util.HashMap;
 import java.util.List;
 
-import com.ruoyi.ams.order.domain.WmsDocOrderDetails;
-import com.ruoyi.base.domain.BaseSku;
-
 /**
  * 出库单Service接口
  *
@@ -104,5 +103,31 @@ public interface IWmsDocOrderDetailsService {
      * @param quantityDecimal
      * @return
      */
-    WmsDocOrderDetails createOrderDetail(String orderNo, BigDecimal lineNo, String sku, BigDecimal quantityDecimal);
+    WmsDocOrderDetails createOrderDetail(String orderNo, String sku, BigDecimal quantityDecimal, Boolean isOnTank);
+
+    /**
+     * 创建出库单详情
+     * @author chenyang
+     * @param orderNo
+     * @param sku
+     * @param quantityDecimal
+     * @param onTankMark
+     * @return
+     */
+    WmsDocOrderDetails createOrderDetail(String orderNo, BigDecimal lineNo, String sku, BigDecimal quantityDecimal, String onTankMark);
+
+    /**
+     * 查询当前有无该物料新建的出库单(搅拌槽)
+     * @param skuChemicalName
+     * @param orderStatus
+     * @return
+     */
+    List<WmsDocOrderDetails> selectWmsDocOrderDetailList(String skuChemicalName, String orderStatus);
+
+    /**
+     * 查询当前有无该物料未完成的出库单(搅拌槽)
+     * @param skuChemicalName
+     * @return
+     */
+    List<WmsDocOrderDetails> selectWmsDocOrderDetailList(String skuChemicalName);
 }

+ 8 - 4
warewms-ams/src/main/java/com/ruoyi/ams/order/service/IWmsDocOrderHeaderService.java

@@ -1,16 +1,19 @@
 package com.ruoyi.ams.order.service;
 
-import java.util.List;
-
 import com.ruoyi.ams.order.domain.WmsDocOrderDetails;
 import com.ruoyi.ams.order.domain.WmsDocOrderExportTime;
 import com.ruoyi.ams.order.domain.WmsDocOrderHeader;
-import com.ruoyi.ams.order.form.*;
+import com.ruoyi.ams.order.form.ArrangeStockForm;
+import com.ruoyi.ams.order.form.CheckOutForm;
+import com.ruoyi.ams.order.form.InvTallyForm;
+import com.ruoyi.ams.order.form.PickForm;
 import com.ruoyi.ams.order.vo.CheckOutVO;
 import com.ruoyi.ams.order.vo.PickingListVO;
 import com.ruoyi.ams.order.vo.StockOrderVO;
 import com.ruoyi.common.core.domain.AjaxResult;
 
+import java.util.List;
+
 /**
  * 出库单头Service接口
  *
@@ -220,7 +223,8 @@ public interface IWmsDocOrderHeaderService {
      * @param orderNo
      * @param orderType
      * @param orderStatus
+     * @param skuChemicalName
      * @return
      */
-    WmsDocOrderHeader createOrderHeader(String orderNo, String orderType, String orderStatus);
+    WmsDocOrderHeader createOrderHeader(String orderNo, String orderType, String orderStatus, String skuChemicalName);
 }

+ 28 - 2
warewms-ams/src/main/java/com/ruoyi/ams/order/service/impl/WmsDocOrderDetailsServiceImpl.java

@@ -1,9 +1,11 @@
 package com.ruoyi.ams.order.service.impl;
 
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.ruoyi.ams.order.domain.WmsDocOrderDetails;
 import com.ruoyi.ams.order.mapper.WmsDocOrderDetailsMapper;
 import com.ruoyi.ams.order.service.IWmsDocOrderDetailsService;
 import com.ruoyi.base.constant.Constant;
+import com.ruoyi.common.constant.Constants;
 import com.ruoyi.common.exception.ServiceException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -25,6 +27,7 @@ public class WmsDocOrderDetailsServiceImpl implements IWmsDocOrderDetailsService
     @Autowired
     private WmsDocOrderDetailsMapper wmsDocOrderDetailsMapper;
 
+
     /**
      * 查询出库单
      *
@@ -151,11 +154,16 @@ public class WmsDocOrderDetailsServiceImpl implements IWmsDocOrderDetailsService
 
     @Override
     public WmsDocOrderDetails createOrderDetail(String orderNo, String sku, BigDecimal quantityDecimal){
-        return createOrderDetail(orderNo, BigDecimal.ONE, sku, quantityDecimal);
+        return createOrderDetail(orderNo, sku, quantityDecimal, Boolean.FALSE);
+    }
+
+    @Override
+    public WmsDocOrderDetails createOrderDetail(String orderNo, String sku, BigDecimal quantityDecimal, Boolean isOnTank){
+        return createOrderDetail(orderNo, BigDecimal.ONE, sku, quantityDecimal, isOnTank ? Constants.AGITATED_TANK : Constants.NORMAL);
     }
 
     @Override
-    public WmsDocOrderDetails createOrderDetail(String orderNo, BigDecimal lineNo, String sku, BigDecimal quantityDecimal) {
+    public WmsDocOrderDetails createOrderDetail(String orderNo, BigDecimal lineNo, String sku, BigDecimal quantityDecimal, String onTankMark) {
         WmsDocOrderDetails wmsDocOrderDetails = new WmsDocOrderDetails();
         wmsDocOrderDetails.setOrderNo(orderNo);
         wmsDocOrderDetails.setOrderLineNo(lineNo);
@@ -167,8 +175,26 @@ public class WmsDocOrderDetailsServiceImpl implements IWmsDocOrderDetailsService
         wmsDocOrderDetails.setQtyPicked(BigDecimal.ZERO);
         wmsDocOrderDetails.setCreateTime(new Date());
         wmsDocOrderDetails.setQtyOrdered(quantityDecimal);
+        wmsDocOrderDetails.setUserdefine1(onTankMark);
         wmsDocOrderDetailsMapper.insertWmsDocOrderDetails(wmsDocOrderDetails);
         return wmsDocOrderDetails;
     }
 
+
+    @Override
+    public List<WmsDocOrderDetails> selectWmsDocOrderDetailList(String skuChemicalName, String orderStatus) {
+        return wmsDocOrderDetailsMapper.selectList(Wrappers.<WmsDocOrderDetails>lambdaQuery()
+                .eq(WmsDocOrderDetails::getSku, skuChemicalName)
+                .eq(WmsDocOrderDetails::getUserdefine1, Constants.AGITATED_TANK)
+                .eq(WmsDocOrderDetails::getLineStatus, orderStatus));
+    }
+
+    @Override
+    public List<WmsDocOrderDetails> selectWmsDocOrderDetailList(String skuChemicalName) {
+        return wmsDocOrderDetailsMapper.selectList(Wrappers.<WmsDocOrderDetails>lambdaQuery()
+                .eq(WmsDocOrderDetails::getSku, skuChemicalName)
+                .eq(WmsDocOrderDetails::getUserdefine1, Constants.AGITATED_TANK)
+                .ne(WmsDocOrderDetails::getLineStatus, Constant.ORDER_STS.STS40.getValue()));
+    }
+
 }

+ 16 - 5
warewms-ams/src/main/java/com/ruoyi/ams/order/service/impl/WmsDocOrderHeaderServiceImpl.java

@@ -21,6 +21,7 @@ import com.ruoyi.ams.inv.service.IInvLotLocIdService;
 import com.ruoyi.ams.order.domain.ActAllocationDetails;
 import com.ruoyi.ams.order.domain.WmsDocOrderDetails;
 import com.ruoyi.ams.order.domain.WmsDocOrderExportTime;
+import com.ruoyi.ams.order.domain.WmsDocOrderHeader;
 import com.ruoyi.ams.order.form.*;
 import com.ruoyi.ams.order.mapper.WmsDocOrderDetailsMapper;
 import com.ruoyi.ams.order.mapper.WmsDocOrderHeaderMapper;
@@ -47,9 +48,6 @@ import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.uuid.SnowflakeIdWorker;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-import com.ruoyi.ams.order.mapper.WmsDocOrderHeaderMapper;
-import com.ruoyi.ams.order.domain.WmsDocOrderHeader;
-import com.ruoyi.ams.order.service.IWmsDocOrderHeaderService;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
@@ -98,6 +96,18 @@ public class WmsDocOrderHeaderServiceImpl implements IWmsDocOrderHeaderService {
     @Autowired
     private IBaseLocationInfoService baseLocationInfoService;
 
+
+    private static final Map<String, String> skuToUnpackMachineNoMapper = new HashMap<String, String>(){
+        {
+
+            put("Na2CO3", "1");//碳酸钠
+            put("C5H10OS2", "2");//丁黄药
+            put("(NaPO3)6", "3");//六偏磷酸钠
+            put("(NH4)2SO4", "4");//硫酸铵
+            put("CH3CH2OCS2Na", "5");//乙黄药
+        }
+    };
+
     /**
      * 查询出库单头
      *
@@ -763,13 +773,14 @@ public class WmsDocOrderHeaderServiceImpl implements IWmsDocOrderHeaderService {
     }
 
     @Override
-    public WmsDocOrderHeader createOrderHeader(String orderNo, String orderType, String orderStatus) {
+    public WmsDocOrderHeader createOrderHeader(String orderNo, String orderType, String orderStatus, String skuChemicalName) {
         WmsDocOrderHeader wmsDocOrderHeader = new WmsDocOrderHeader();
         wmsDocOrderHeader.setOrderNo(orderNo);
         wmsDocOrderHeader.setEdiSendFlag(Constants.NO);
         wmsDocOrderHeader.setOrderStatus(Constant.ORDER_STS.STS00.getValue());
         wmsDocOrderHeader.setCreateTime(DateUtil.date());
-        wmsDocOrderHeader.setOrderType(Constant.ORDER_TYP.DZ.getValue());
+        wmsDocOrderHeader.setOrderType(orderType);
+        wmsDocOrderHeader.setSoReference3(skuToUnpackMachineNoMapper.get(skuChemicalName));
         wmsDocOrderHeaderMapper.insertWmsDocOrderHeader(wmsDocOrderHeader);
         return wmsDocOrderHeader;
     }

+ 6 - 2
warewms-ams/src/main/java/com/ruoyi/ams/task/service/impl/WcsTaskServiceImpl.java

@@ -428,7 +428,9 @@ public class WcsTaskServiceImpl implements IWcsTaskService {
                         // 将起始点库存移动到中间缓存位
                         moveStartingPointToMiddleCache(wcsTask);
                         //agv回调wcs取货完成
-                        wmsDocAsnSubService.callbackWcsAgvOutTask(taskNo);
+                        if(StringUtils.startsWith(wcsTask.getExt1(), "SO")) {
+                            wmsDocAsnSubService.callbackWcsAgvOutTask(taskNo);
+                        }
                         //释放redis锁
                         if (!StringUtils.isEmpty(wcsTask.getExt8())) {
                             redisCache.unlockCacheObject(Long.parseLong(wcsTask.getExt8()), wcsTask.getLocationFrom());
@@ -451,7 +453,9 @@ public class WcsTaskServiceImpl implements IWcsTaskService {
                             // 修改库存标识标识 因为接驳位可以出库也可以入库 所以需要标识当前接驳位的库存是入库还是出库
                             updateInvAsnSoMarking(wcsTask);
                             //agv回调wcs卸货完成
-                            wmsDocAsnSubService.callbackWcsAgvInTask(taskNo);
+                            if(StringUtils.startsWith(wcsTask.getExt1(), "ASN")) {
+                                wmsDocAsnSubService.callbackWcsAgvInTask(taskNo);
+                            }
                             //释放redis锁
                             if (!StringUtils.isEmpty(wcsTask.getExt8())) {
                                 redisCache.unlockCacheObject(Long.parseLong(wcsTask.getExt8()));

+ 71 - 0
warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/domain/dto/SkuAgitatedTankAttrDTO.java

@@ -0,0 +1,71 @@
+package com.ruoyi.ams.xuankuang.domain.dto;
+
+import com.ruoyi.hard.xuankang.StirringTankClient;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 物料对应的搅拌槽业务信息
+ */
+@Data
+@Accessors(chain = true)
+public class SkuAgitatedTankAttrDTO implements Serializable {
+
+    private static final long serialVersionUID = 3296609400419603808L;
+
+
+    /**
+     * 物料化学名称(英文),如
+     */
+    private String skuChemicalName;
+
+    /**
+     * 该物料的换算比率
+     */
+    private Integer rate;
+
+    /**
+     * 读搅拌槽所需物料剂量的指令
+     */
+    private StirringTankClient.STIR_TANK_COMMAND readDosageCommand;
+
+    /**
+     * 无法注入药量的点位索引
+     */
+    private Integer unableBitIndex;
+
+    /**
+     * 可以注入药量的点位索引
+     */
+    private Integer ableBitIndex;
+
+
+    /**
+     * 开始执行任务的点位索引
+     */
+    private Integer startBitIndex;
+
+    /**
+     * 任务开始执行的点位索引
+     */
+    private Integer runBitIndex;
+
+    /**
+     * 任务执行错误的点位索引
+     */
+    private Integer errorBitIndex;
+
+    /**
+     * 任务执行失败的点位索引
+     */
+    private Integer endBitIndex;
+
+    /**
+     * 确认任务是否需要执行的点位索引
+     */
+    private Integer confirmBitIndex;
+
+
+}

+ 15 - 1
warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/facade/impl/UnpackingMachineFacadeImpl.java

@@ -1,5 +1,6 @@
 package com.ruoyi.ams.xuankuang.facade.impl;
 
+import cn.hutool.core.util.BooleanUtil;
 import com.ruoyi.ams.xuankuang.domain.form.CallbackBbmForm;
 import com.ruoyi.ams.xuankuang.facade.IUnpackingMachineFacade;
 import com.ruoyi.ams.xuankuang.service.WmsToWcsApiService;
@@ -7,6 +8,7 @@ import com.ruoyi.common.exception.base.BaseException;
 import com.ruoyi.hard.xuankang.StirringTankClient;
 import com.ruoyi.hard.xuankang.UnpackingMachineSubClient;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ArrayUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.util.Assert;
@@ -28,12 +30,24 @@ public class UnpackingMachineFacadeImpl implements IUnpackingMachineFacade {
     public Boolean unpackingMachineOpen(String lineId, boolean[] booleans){
         //Assert.isTrue(verifyLineOpenStatus(lineId, booleans), "method [verifyLineOpenStatus] return false ");
         verifyLineOpenStatus(lineId, booleans);
-        Assert.isTrue(unpackingMachineSubClientWrite(lineId), "method [unpackingMachineSubClientWrite] return false ");
+        Assert.isTrue(unpackingMachineSubClientWrite(lineId), "method [unpackingMachineSubClientWrite] return false");
+        Assert.isTrue(isCutOffToolOpen(lineId), "method [isCutOffToolOpen] return false");
         wmsCallback(lineId);
         stirringTankClientWrite(lineId);
         return Boolean.TRUE;
     }
 
+
+    /**
+     * 拆包机割刀是否正常
+     */
+    public Boolean isCutOffToolOpen(String lineId){
+        Boolean[] cutOffToolStatus = unpackingMachineSubClient.readCutOffToolStatus(lineId);
+        return BooleanUtil.and(ArrayUtils.toPrimitive(cutOffToolStatus));
+    }
+
+
+
     private Boolean verifyLineOpenStatus(String lineId, boolean[] booleans) {
         switch (lineId) {
             case "1":

+ 3 - 3
warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/service/AgvCallProxyService.java

@@ -150,7 +150,7 @@ public class AgvCallProxyService {
 
         //3.出库单创建
         WmsDocOrderHeader docOrderHeader =
-                iWmsDocOrderHeaderService.createOrderHeader(orderNo, Constant.ORDER_TYP.TZ.getValue(), Constant.ORDER_STS.STS00.getValue());
+                iWmsDocOrderHeaderService.createOrderHeader(orderNo, Constant.ORDER_TYP.TZ.getValue(), Constant.ORDER_STS.STS00.getValue(), baseSku.getSku());
         WmsDocOrderDetails docOrderDetail =
                 iWmsDocOrderDetailsService.createOrderDetail(orderNo, baseSku.getSku(), quantityDecimal);
 
@@ -200,7 +200,7 @@ public class AgvCallProxyService {
 
         //3.出库单创建
         String orderNo = idSequenceUtils.generateId(Constant.ID_TYPE.ORDERNO.getDesc());
-        iWmsDocOrderHeaderService.createOrderHeader(orderNo, Constant.ORDER_TYP.TZ.getValue(), Constant.ORDER_STS.STS40.getValue());
+        iWmsDocOrderHeaderService.createOrderHeader(orderNo, Constant.ORDER_TYP.TZ.getValue(), Constant.ORDER_STS.STS40.getValue(), baseSku.getSku());
         iWmsDocOrderDetailsService.createOrderDetail(orderNo, baseSku.getSku(), quantityDecimal);
 
         //2. 获取agv的库位,并创建agv的wcs任务
@@ -272,7 +272,7 @@ public class AgvCallProxyService {
         // 3.生成任务
         addWcsTask(taskNo, bucketCacheLocationId
                 , String.valueOf(baseLocationInfo.getId()), asnNo, palletNo,
-                Constant.TASK_STS.TASK_PUBILSH.getLongValue(), "四向车入库任务",
+                Constant.TASK_STS.TASK_PUBILSH.getLongValue(), "桶装料入库任务",
                 Constant.TaskType.RGV.getDesc());
         //4.同步当前的wcs任务
         AgvInTaskForm agvInTaskForm = assemblyAgvInTaskForm(taskNo, asnNo, materialType, quantity, palletNo, baseLocationInfo);

+ 18 - 0
warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/service/IAgitatedTankService.java

@@ -0,0 +1,18 @@
+package com.ruoyi.ams.xuankuang.service;
+
+
+public interface IAgitatedTankService {
+
+
+    /**
+     * 查询搅拌槽生产任务请求以及生成出库单
+     * @param skuChemicalName
+     */
+    void agitateTankCreateOrderTask(String skuChemicalName);
+
+    /**
+     * 执行搅拌槽生产任务请求
+     * @param skuChemicalName
+     */
+    void agitateTankExcuteTask(String skuChemicalName);
+}

+ 98 - 5
warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/service/StirringTankClientService.java

@@ -1,20 +1,22 @@
 package com.ruoyi.ams.xuankuang.service;
 
 
-import com.ruoyi.ams.asn.domain.WmsDocAsnDetails;
-import com.ruoyi.ams.order.domain.WmsDocOrderDetails;
+import cn.hutool.core.util.NumberUtil;
 import com.ruoyi.ams.order.domain.WmsDocOrderHeader;
-import com.ruoyi.ams.order.mapper.WmsDocOrderDetailsMapper;
 import com.ruoyi.ams.order.mapper.WmsDocOrderHeaderMapper;
-import com.ruoyi.base.constant.Constant;
+import com.ruoyi.ams.xuankuang.domain.dto.SkuAgitatedTankAttrDTO;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.hard.xuankang.StirringTankClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
-import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static com.ruoyi.hard.xuankang.StirringTankClient.STIR_TANK_COMMAND.*;
 
 /**
  * @author Jwk
@@ -34,6 +36,94 @@ public class StirringTankClientService {
     @Autowired
     WmsDocOrderHeaderMapper wmsDocOrderHeaderMapper;
 
+    //物料的换算比率映射 PS: 换算比例 Rate=20 代表一份物料20kg
+    private static final  Map<String, SkuAgitatedTankAttrDTO> skuToAgitatedTankAttrMapper = new HashMap<String, SkuAgitatedTankAttrDTO>(){
+        {
+            put("C5H10OS2", new SkuAgitatedTankAttrDTO().setReadDosageCommand(READ_THE_STIRRING_TANK_08)
+                    .setRate(25).setUnableBitIndex(1).setAbleBitIndex(1).setStartBitIndex(1)
+                    .setRunBitIndex(1).setErrorBitIndex(1).setEndBitIndex(1).setConfirmBitIndex(1));//丁黄药
+            put("(NaPO3)6", new SkuAgitatedTankAttrDTO().setReadDosageCommand(READ_THE_STIRRING_TANK_10)
+                    .setRate(20).setUnableBitIndex(3).setAbleBitIndex(3).setStartBitIndex(3)
+                    .setRunBitIndex(3).setErrorBitIndex(3).setEndBitIndex(3).setConfirmBitIndex(3));//六偏磷酸钠
+            put("(NH4)2SO4", new SkuAgitatedTankAttrDTO().setReadDosageCommand(READ_THE_STIRRING_TANK_11)
+                    .setRate(20).setUnableBitIndex(4).setAbleBitIndex(4).setStartBitIndex(4)
+                    .setRunBitIndex(4).setErrorBitIndex(4).setEndBitIndex(4).setConfirmBitIndex(4));//硫酸铵
+            put("CH3CH2OCS2Na", new SkuAgitatedTankAttrDTO().setReadDosageCommand(READ_THE_STIRRING_TANK_06)
+                    .setRate(25).setUnableBitIndex(5).setAbleBitIndex(5).setStartBitIndex(5)
+                    .setRunBitIndex(5).setErrorBitIndex(5).setEndBitIndex(5).setConfirmBitIndex(5));//乙黄药
+        }
+    };
+
+    public static final List<String> getSkuList(){
+        return skuToAgitatedTankAttrMapper.keySet().stream().collect(Collectors.toList());
+    }
+
+    public Boolean setTaskEnd(String skuChemicalName) {
+        SkuAgitatedTankAttrDTO skuAgitatedTankAttrDTO = skuToAgitatedTankAttrMapper.get(skuChemicalName);
+        return stirringTankClient.writeTaskEnd(skuAgitatedTankAttrDTO.getEndBitIndex());
+    }
+
+    public Boolean setTaskError(String skuChemicalName) {
+        SkuAgitatedTankAttrDTO skuAgitatedTankAttrDTO = skuToAgitatedTankAttrMapper.get(skuChemicalName);
+        return stirringTankClient.writeTaskError(skuAgitatedTankAttrDTO.getErrorBitIndex());
+    }
+
+    public Boolean setTaskRun(String skuChemicalName) {
+        SkuAgitatedTankAttrDTO skuAgitatedTankAttrDTO = skuToAgitatedTankAttrMapper.get(skuChemicalName);
+        return stirringTankClient.writeTaskRun(skuAgitatedTankAttrDTO.getRunBitIndex());
+    }
+
+    /**
+     * 写无法注入
+     */
+    public Boolean setUnableInject(String skuChemicalName){
+        SkuAgitatedTankAttrDTO skuAgitatedTankAttrDTO = skuToAgitatedTankAttrMapper.get(skuChemicalName);
+        return stirringTankClient.writeUnableInject(skuAgitatedTankAttrDTO.getUnableBitIndex());
+    }
+
+    /**
+     * 写可以注入
+     * @param skuChemicalName
+     * @return
+     */
+    public Boolean setAbleInject(String skuChemicalName){
+        SkuAgitatedTankAttrDTO skuAgitatedTankAttrDTO = skuToAgitatedTankAttrMapper.get(skuChemicalName);
+        return stirringTankClient.writeAbleInject(skuAgitatedTankAttrDTO.getAbleBitIndex());
+    }
+
+
+    /**
+     * 确认是否现在就需要生成任务
+     * @param skuChemicalName
+     * @return
+     */
+    public Boolean confirmNeedNow(String skuChemicalName) {
+        SkuAgitatedTankAttrDTO skuAgitatedTankAttrDTO = skuToAgitatedTankAttrMapper.get(skuChemicalName);
+        return stirringTankClient.readConfirmNeedMark(skuAgitatedTankAttrDTO.getConfirmBitIndex());
+    }
+
+    /**
+     * 确认是否可以执行出库任务
+     * @param skuChemicalName
+     * @return
+     */
+    public Boolean enableExcuteTask(String skuChemicalName) {
+        SkuAgitatedTankAttrDTO skuAgitatedTankAttrDTO = skuToAgitatedTankAttrMapper.get(skuChemicalName);
+        return stirringTankClient.readExcuteTaskMark(skuAgitatedTankAttrDTO.getStartBitIndex());
+    }
+
+    /**
+     * 读取并计算物料的使用剂量转换为物料袋数
+     * @param skuChemicalName 物料化学名称
+     * @return
+     */
+    public BigDecimal getNeededInvQuantity(String skuChemicalName){
+        SkuAgitatedTankAttrDTO skuAgitatedTankAttrDTO = skuToAgitatedTankAttrMapper.get(skuChemicalName);
+        Number neededWeightCount = stirringTankClient.readNeedDosage(skuAgitatedTankAttrDTO.getReadDosageCommand());
+        return NumberUtil.div(neededWeightCount, skuAgitatedTankAttrDTO.getRate(), 0);
+    }
+
+
     /**
      * 对比碳酸钠库存
      *
@@ -483,5 +573,8 @@ public class StirringTankClientService {
         }
         return AjaxResult.success();
     }
+
+
+
 }
 

+ 10 - 2
warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/service/WcsTaskSubService.java

@@ -22,6 +22,7 @@ import com.ruoyi.ams.task.service.IWcsTaskService;
 import com.ruoyi.base.constant.Constant;
 import com.ruoyi.base.domain.BaseLocationInfo;
 import com.ruoyi.base.service.IBaseLocationInfoService;
+import com.ruoyi.common.constant.Constants;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.exception.base.BaseException;
 import com.ruoyi.common.utils.StringUtils;
@@ -63,6 +64,8 @@ public class WcsTaskSubService {
     private WmsDocOrderHeaderMapper wmsDocOrderHeaderMapper;
     @Autowired
     private WmsDocAsnSubService wmsDocAsnSubService;
+    @Autowired
+    private StirringTankClientService stirringTankClientService;
 
 
     public AjaxResult addWcsTask(String taskNo, String locationFrom, String locationTo
@@ -373,8 +376,13 @@ public class WcsTaskSubService {
         if (ObjectUtil.equal(Boolean.TRUE, isComplete)) {
             updateWmsDocOrderHeader(orderNo, docOrderDetail.getSku());
             if(!StringUtils.equals(Constant.TaskType.RGV.getDesc(), wcsTask.getWhTypeFrom())){
+                log.info("turn off the unpacker, cucrrent sku is {}", docOrderDetail.getSku());
                 turnOffTheUnpacker(docOrderDetail.getSku());
             }
+            if(StringUtils.equals(Constants.AGITATED_TANK, docOrderDetail.getUserdefine1())){
+                log.info("agitated tank task is finish, cucrrent sku is {}", docOrderDetail.getSku());
+                stirringTankClientService.setTaskEnd(docOrderDetail.getSku());
+            }
         } else {
             WmsDocOrderHeader wmsDocOrderHeader = iWmsDocOrderHeaderService.selectWmsDocOrderHeaderByOrderNo(orderNo);
             // 修改 单头30
@@ -405,11 +413,11 @@ public class WcsTaskSubService {
 
     /**
      * 越库完成后回调
-     *
+     * TODO chenyang
      * @param wcsTask
      * @return
      */
-    //TODO  陈阳
+
     public AjaxResult completeTheCallbackYueKu(WcsTask wcsTask) {
 
         String asnNo = wcsTask.getExt1();

+ 67 - 25
warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/service/WmsDocOrderSubService.java

@@ -3,11 +3,13 @@ package com.ruoyi.ams.xuankuang.service;
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.collection.ListUtil;
 import cn.hutool.core.comparator.CompareUtil;
+import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.NumberUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.toolkit.IdWorker;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 import com.ruoyi.ams.asn.domain.WmsDocAsnDetails;
 import com.ruoyi.ams.asn.service.IWmsDocAsnHeaderService;
 import com.ruoyi.ams.config.domain.dto.LotattDTO;
@@ -105,7 +107,7 @@ public class WmsDocOrderSubService {
         //筛选库存 由于选矿项目出库单头只对应一个
         Boolean orderRule = getOrderRule();
         List<BaseLocationLotattDTO> filteredLocationLotattList = orderRule
-                ? selectInventoriesByLocation(baseLocationLotattList, list.get(0)) : filterInv(baseLocationLotattList, orderNo);
+                ?   selectInventoriesByLocation(baseLocationLotattList, list.get(0)) : filterInv(baseLocationLotattList, orderNo);
         // 匹配库存(撇开先进先出)
 //        baseLocationLotattVOS = addConfirmAllocationAuto(orderNo);
 
@@ -246,17 +248,11 @@ public class WmsDocOrderSubService {
             int locationIndex = partitionLocationIdList.indexOf(locationInfo.getId());
             if(StringUtils.equals(partitionRowKey, Constants.FIRST)) {
                 List<Long> firstRightSubList = ListUtil.reverse(ListUtil.sub(partitionLocationIdList, locationIndex, partitionLocationIdList.size()));
-                List<Long> resultLocationIdList = checkLocationIdList(locationInfo.getId(), sourceInvLotLocIdList, firstRightSubList,
+                Map<String, Object> allocateLocationInfo = allocateLocationIdList(locationInfo.getId(), sourceInvLotLocIdList, firstRightSubList,
                         baseLocationLotattList, quantity);
-                if(CollectionUtil.isEmpty(resultLocationIdList)) continue;
-                BigDecimal firstRightCount = sourceInvLotLocIdList.stream()
-                        .filter(item -> CollectionUtil.contains(resultLocationIdList, Long.parseLong(item.getLocationId()))
-                                && ObjectUtil.isNotNull(item.getQty()))
-                        .map(item -> item.getQty()).reduce(BigDecimal.ZERO, BigDecimal::add);
-                quantity = NumberUtil.sub(quantity, firstRightCount);
-                baseLocationLotattList = baseLocationLotattList.stream()
-                        .filter(item -> !CollectionUtil.contains(resultLocationIdList, item.getId())).collect(Collectors.toList());
-                selectedLocationIdList.addAll(resultLocationIdList);
+                baseLocationLotattList = (List<BaseLocationLotattDTO>) allocateLocationInfo.get("baseLocationLotattList");
+                quantity = (BigDecimal) allocateLocationInfo.get("quantity");
+                CollectionUtil.addAll(selectedLocationIdList, (List<Long>) allocateLocationInfo.get("resultLocationIdList"));
                 if(CompareUtil.compare(quantity, BigDecimal.ZERO) <= 0) break;
             }
 
@@ -292,24 +288,18 @@ public class WmsDocOrderSubService {
 
                 baseLocationLotattList = baseLocationLotattList.stream()
                         .filter(item -> !CollectionUtil.contains(finalLeftLocationIdList, item.getId())).collect(Collectors.toList());
-                selectedLocationIdList.addAll(finalLeftLocationIdList);
+                CollectionUtil.addAll(selectedLocationIdList, finalLeftLocationIdList);
+
                 if(CompareUtil.compare(quantity, BigDecimal.ZERO) <= 0) break;
             }
 
             if(StringUtils.equals(partitionRowKey, Constants.LAST)) {
                 List<Long> lastLeftSubList = ListUtil.sub(partitionLocationIdList, Constants.START_VALUE, locationIndex + 1);
-                List<Long> lastLeftLocationIdList = checkLocationIdList(locationInfo.getId(), sourceInvLotLocIdList, lastLeftSubList,
+                Map<String, Object> allocateLocationInfo = allocateLocationIdList(locationInfo.getId(), sourceInvLotLocIdList, lastLeftSubList,
                         baseLocationLotattList, quantity);
-                if(CollectionUtil.isEmpty(lastLeftLocationIdList)) continue;
-                BigDecimal lastLeftCount = sourceInvLotLocIdList.stream()
-                        .filter(item -> CollectionUtil.contains(lastLeftLocationIdList, Long.parseLong(item.getLocationId()))
-                                && ObjectUtil.isNotNull(item.getQty()))
-                        .map(item -> item.getQty()).reduce(BigDecimal.ZERO, BigDecimal::add);
-
-                quantity = NumberUtil.sub(quantity, lastLeftCount);
-                baseLocationLotattList = baseLocationLotattList.stream()
-                        .filter(item -> !CollectionUtil.contains(lastLeftLocationIdList, item.getId())).collect(Collectors.toList());
-                selectedLocationIdList.addAll(lastLeftLocationIdList);
+                baseLocationLotattList = (List<BaseLocationLotattDTO>) allocateLocationInfo.get("baseLocationLotattList");
+                quantity = (BigDecimal) allocateLocationInfo.get("quantity");
+                CollectionUtil.addAll(selectedLocationIdList, (List<Long>) allocateLocationInfo.get("resultLocationIdList"));
                 if(CompareUtil.compare(quantity, BigDecimal.ZERO) <= 0) break;
             }
         }
@@ -320,6 +310,23 @@ public class WmsDocOrderSubService {
                 ).filter(item -> ObjectUtil.isNotNull(item)).collect(Collectors.toList());
     }
 
+    private Map<String, Object> allocateLocationIdList(Long locationId, List<InvLotLocId> sourceInvLotLocIdList, List<Long> subList, List<BaseLocationLotattDTO> baseLocationLotattList, BigDecimal quantity) {
+
+        List<Long> resultLocationIdList = checkLocationIdListOnBeside(locationId, sourceInvLotLocIdList, subList,
+                baseLocationLotattList, quantity);
+        if(CollectionUtil.isEmpty(resultLocationIdList)) return Maps.newHashMap();
+        BigDecimal firstRightCount = sourceInvLotLocIdList.stream()
+                .filter(item -> CollectionUtil.contains(resultLocationIdList, Long.parseLong(item.getLocationId()))
+                        && ObjectUtil.isNotNull(item.getQty()))
+                .map(item -> item.getQty()).reduce(BigDecimal.ZERO, BigDecimal::add);
+        quantity = NumberUtil.sub(quantity, firstRightCount);
+        baseLocationLotattList = baseLocationLotattList.stream()
+                .filter(item -> !CollectionUtil.contains(resultLocationIdList, item.getId())).collect(Collectors.toList());
+        return MapUtil.builder(new HashMap<String, Object>()).put("resultLocationIdList", resultLocationIdList)
+                .put("quantity", quantity).put("baseLocationLotattList", baseLocationLotattList).map();
+    }
+
+
     private BigDecimal compareCount(BigDecimal middleLeftCount, BigDecimal middleRightCount) {
         if(CompareUtil.compare(middleLeftCount, middleRightCount) < 0
                 && CompareUtil.compare(middleLeftCount, BigDecimal.ZERO) > 0){
@@ -341,9 +348,44 @@ public class WmsDocOrderSubService {
     }
 
 
+    private List<Long>  checkLocationIdListOnBeside(Long locationId, List<InvLotLocId> sourceInvLotLocIdList, List<Long> subList,
+                                                   List<BaseLocationLotattDTO> baseLocationLotattList, BigDecimal quantity) {
+        List<Long> locationIdList = baseLocationLotattList.stream().map(item -> item.getId()).collect(Collectors.toList());
+        //证明这一列只有这一个 or 证明外侧都是空的
+        List<Long> filteredList = subList.stream()
+                .filter(item -> !ObjectUtil.equal(item, locationId)
+                        && CollectionUtil.contains(locationIdList, item)).collect(Collectors.toList());
+        if(CollectionUtil.isEmpty(filteredList)) return Lists.newArrayList(locationId);
+
+        //查有没有入库任务,存在入库任务,此列不能出库
+        List<BaseLocationInfo> locationInfoList = baseLocationInfoService.selectLocationInfoList(filteredList);
+        List<BaseLocationInfo> asnTaskCheckList = locationInfoList.stream()
+                .filter(item -> StringUtils.equals(item.getStockStatus(), Constant.STOCK_STATUS.STOCK10.getValue())
+                        && StringUtils.equals(item.getIsEmpty(), Constants.YES)).collect(Collectors.toList());
+        if(CollectionUtil.isNotEmpty(asnTaskCheckList)) return Lists.newArrayList();
+
+        //目前还未被推荐的总库存
+        List<InvLotLocId> filterdInvLocIdList = sourceInvLotLocIdList.stream()
+                .filter(item -> CollectionUtil.contains(locationIdList, Long.parseLong(item.getLocationId()))).collect(Collectors.toList());
+        //当前列的库存
+        List<InvLotLocId> currentRowInvList = filterdInvLocIdList.stream()
+                .filter(item -> CollectionUtil.contains(subList, Long.parseLong(item.getLocationId()))).collect(Collectors.toList());
+        BigDecimal currentRowInvCount = currentRowInvList.stream().filter(item -> ObjectUtil.isNotNull(item.getQty()))
+                .map(item -> item.getQty()).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
+        List<InvLotLocId> exceptCurrentInvIdList = filterdInvLocIdList.stream()
+                .filter(item -> !StringUtils.equals(item.getLocationId(), NumberUtil.toStr(locationId))).collect(Collectors.toList());
+        BigDecimal exceptCurrentLocationInvCount = exceptCurrentInvIdList.stream().filter(item -> ObjectUtil.isNotNull(item.getQty()))
+                .map(item -> item.getQty()).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
+        List<Long> invIdList = currentRowInvList.stream().map(item -> Long.parseLong(item.getLocationId())).collect(Collectors.toList());
+
+        return CompareUtil.compare(currentRowInvCount, quantity) < 0
+                || CompareUtil.compare(exceptCurrentLocationInvCount, quantity) < 0
+                ? subList.stream().filter(item -> CollectionUtil.contains(invIdList, item)).collect(Collectors.toList())
+                : Lists.newArrayList();
+    }
+
     private List<Long> checkLocationIdList(Long locationId, List<InvLotLocId> sourceInvLotLocIdList, List<Long> subList,
                                            List<BaseLocationLotattDTO> baseLocationLotattList, BigDecimal quantity) {
-        //要过滤掉已经推荐的库存
         List<Long> locationIdList = baseLocationLotattList.stream().map(item -> item.getId()).collect(Collectors.toList());
         //证明这一列只有这一个 or 证明外侧都是空的
         List<Long> filteredList = subList.stream()
@@ -358,7 +400,7 @@ public class WmsDocOrderSubService {
                         && StringUtils.equals(item.getIsEmpty(), Constants.YES)).collect(Collectors.toList());
         if(CollectionUtil.isNotEmpty(asnTaskCheckList)) return Lists.newArrayList();
 
-        //要过滤掉已经推荐的库存
+        //比较数量,决定最终是否可以推荐
         List<InvLotLocId> invLocIdList = sourceInvLotLocIdList.stream()
                 .filter(item -> CollectionUtil.contains(locationIdList, Long.parseLong(item.getLocationId())))
                 .filter(item -> CollectionUtil.contains(subList, Long.parseLong(item.getLocationId()))).collect(Collectors.toList());

+ 102 - 0
warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/service/impl/AgitatedTankServiceImpl.java

@@ -0,0 +1,102 @@
+package com.ruoyi.ams.xuankuang.service.impl;
+
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.NumberUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.ruoyi.ams.config.domain.dto.LotattDTO;
+import com.ruoyi.ams.order.domain.WmsDocOrderDetails;
+import com.ruoyi.ams.order.service.IWmsDocOrderDetailsService;
+import com.ruoyi.ams.order.service.IWmsDocOrderHeaderService;
+import com.ruoyi.ams.xuankuang.service.BaseLocationInfoSubService;
+import com.ruoyi.ams.xuankuang.service.IAgitatedTankService;
+import com.ruoyi.ams.xuankuang.service.StirringTankClientService;
+import com.ruoyi.ams.xuankuang.service.WmsDocOrderSubService;
+import com.ruoyi.base.constant.Constant;
+import com.ruoyi.base.domain.vo.BaseLocationLotattDTO;
+import com.ruoyi.base.utils.IdSequenceUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.compress.utils.Lists;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.interceptor.TransactionAspectSupport;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import static com.ruoyi.ams.xuankuang.service.BaseLocationInfoSubService.OUT_ZONES;
+
+
+@Service
+@Slf4j
+public class AgitatedTankServiceImpl implements IAgitatedTankService {
+
+
+    @Autowired
+    private StirringTankClientService stirringTankClientService;
+
+    @Autowired
+    private BaseLocationInfoSubService baseLocationInfoSubService;
+
+    @Autowired
+    private IWmsDocOrderHeaderService iWmsDocOrderHeaderService;
+
+    @Autowired
+    private IWmsDocOrderDetailsService iWmsDocOrderDetailsService;
+
+    @Autowired
+    private IdSequenceUtils idSequenceUtils;
+
+    @Autowired
+    private WmsDocOrderSubService wmsDocOrderSubService;
+
+    @Override
+    public void agitateTankCreateOrderTask(String skuChemicalName) {
+        try{
+            //1.读取有无该物料的关于搅拌槽的未完成出库单如有就不生成
+            if(CollectionUtil.isNotEmpty(iWmsDocOrderDetailsService.selectWmsDocOrderDetailList(skuChemicalName))) return;
+            //2.先确认现在是否需要,再查询当前库存总数够不够
+            Boolean isNeedNow = stirringTankClientService.confirmNeedNow(skuChemicalName);
+            if(!isNeedNow) return;
+            BigDecimal neededQuantity = stirringTankClientService.getNeededInvQuantity(skuChemicalName);
+            List<BaseLocationLotattDTO> baseLocationLotattDTOList
+                    = baseLocationInfoSubService.selectAllocatingInventoryAccordingConditionsOrderBy(OUT_ZONES, new LotattDTO(), skuChemicalName, null);
+            List<BaseLocationLotattDTO> locationLotattList = CollectionUtil.isNotEmpty(baseLocationLotattDTOList) ? baseLocationLotattDTOList : Lists.newArrayList();
+            double invQuantity = locationLotattList.stream().filter(ObjectUtil::isNotNull).mapToDouble(item -> item.getQty()).sum();
+            //3.写搅拌槽可以进行出库请求
+            Boolean isWriteSuccess = NumberUtil.isGreater(neededQuantity, new BigDecimal(invQuantity))
+                    ? stirringTankClientService.setUnableInject(skuChemicalName) : stirringTankClientService.setAbleInject(skuChemicalName);
+            //4.生成出库单
+            if(NumberUtil.isLessOrEqual(neededQuantity, new BigDecimal(invQuantity)) && isWriteSuccess){
+                String orderNo = idSequenceUtils.generateId(Constant.ID_TYPE.ORDERNO.getDesc());
+                iWmsDocOrderHeaderService.createOrderHeader(orderNo, Constant.ORDER_TYP.DZ.getValue(), Constant.ORDER_STS.STS00.getValue(), skuChemicalName);
+                iWmsDocOrderDetailsService.createOrderDetail(orderNo, skuChemicalName, neededQuantity, Boolean.TRUE);
+            }
+        }catch (RuntimeException ex){
+            log.info("Exception of AgitatedTankServiceImpl-agitateTankCreateOrderTask has been thrown, cucrrent time is {}, Caused by {}"
+                    , DateUtil.now(), ex);
+            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
+            return;
+        }
+
+    }
+
+    @Override
+    public void agitateTankExcuteTask(String skuChemicalName) {
+        //查询是否是需要执行该物料的出库任务
+        try{
+            Boolean isEnableExcuteTask = stirringTankClientService.enableExcuteTask(skuChemicalName);
+            if(!isEnableExcuteTask) return;
+            //查询是否有存在的出库单
+            List<WmsDocOrderDetails> wmsDocOrderDetails = iWmsDocOrderDetailsService.selectWmsDocOrderDetailList(skuChemicalName, Constant.ORDER_STS.STS00.getValue());
+            if(CollectionUtil.isEmpty(wmsDocOrderDetails)) return;
+            //出库单同步至Wcs用于开始执行任务
+            wmsDocOrderSubService.initOrderDetails(wmsDocOrderDetails.get(0).getOrderNo());
+            stirringTankClientService.setTaskRun(skuChemicalName);
+        }catch (RuntimeException ex) {
+            log.info("agitateTankExcuteTask_agitateTankExcuteTask is happened, current time is {}, Caused by {}", DateUtil.now(), ex);
+            stirringTankClientService.setTaskError(skuChemicalName);
+        }
+    }
+}

+ 11 - 2
warewms-hard/src/main/java/com/ruoyi/hard/xuankang/ConvertUtil.java

@@ -1,5 +1,7 @@
 package com.ruoyi.hard.xuankang;
 
+import com.alibaba.fastjson.JSONObject;
+
 import java.util.Arrays;
 
 /**
@@ -42,8 +44,15 @@ public class ConvertUtil {
     }
 
     public static void main(String[] args) {
-        boolean[] booleans = {true, true, true, true, true, true, true, true};
-        System.out.println(ConvertUtil.convertToInt(booleans));
+        boolean[] booleans = {true, true, true, false, true, false, true, true};
+
+        int i = ConvertUtil.convertToInt(booleans);
+        System.out.println(i);
+        boolean[] booleans2 = convertToBooleans(i);
+        booleans2[8] = false;
+        booleans2[13] = false;
+        booleans2[2] = true;
+        System.out.println(JSONObject.toJSONString(booleans2));
 
         int num = 23;
         boolean[] booleans1 = convertToBooleans(num);

+ 94 - 6
warewms-hard/src/main/java/com/ruoyi/hard/xuankang/StirringTankClient.java

@@ -1,10 +1,10 @@
 package com.ruoyi.hard.xuankang;
 
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.NumberUtil;
 import com.jwk.spring.boot.autoconfigure.ModbusTcpMasterTemplate;
 import com.jwk.spring.boot.constant.DATA_TYPE_WRAPPER;
 import com.jwk.spring.boot.modbus4j.ModbusMasterUtil;
-import com.serotonin.modbus4j.base.ModbusUtils;
-import com.serotonin.modbus4j.msg.ReadResponse;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
@@ -71,10 +71,12 @@ public class StirringTankClient {
         //读确认开始生产
         READ_THE_STIRRING_TANK_16(1, 115, 1, 0),
 
-        //读仓库无法完成注药量
+        /**
+         * 读仓库无法完成注药量
+         */
         READ_THE_REPOSITORY_01(1, 0, 1, 0),
         //写仓库无法完成注药量
-        WRITE_THE_STIRRING_TANK_01(1, 0, 1, 0),
+        WRITE_THE_STIRRING_TANK_01  (1, 0, 1, 0),
 
         //读仓库确认可完成注药量
         READ_THE_REPOSITORY_02(1, 1, 1, 0),
@@ -137,6 +139,93 @@ public class StirringTankClient {
         }
     }
 
+
+    /**
+     * 读搅拌槽所需的剂量,单位是kg
+     * @param tankCommand
+     * @return
+     */
+    public Number readNeedDosage(STIR_TANK_COMMAND tankCommand){
+        Number needInvQuantity = read1(tankCommand.getSlaveId(), tankCommand.getOffset());
+        log.info("readNeedDosage result is {}", needInvQuantity);
+        return NumberUtil.mul(NumberUtil.div(needInvQuantity, 100, 2), 1000);
+    }
+
+
+    public Boolean readExcuteTaskMark(int bitIndex) {
+        Number number = read1(READ_THE_STIRRING_TANK_14.getSlaveId(), READ_THE_STIRRING_TANK_14.getOffset());
+        boolean[] excuteTaskMarkArray = ArrayUtil.reverse(ConvertUtil.convertToBooleans(number));
+        log.info("readExcuteTaskMark result is {}", excuteTaskMarkArray[bitIndex]);
+        return excuteTaskMarkArray[bitIndex];
+    }
+
+    public Boolean readConfirmNeedMark(Integer bitIndex) {
+        Number number = read1(READ_THE_STIRRING_TANK_13.getSlaveId(), READ_THE_STIRRING_TANK_13.getOffset());
+        boolean[] confirmNeedMarkArray = ArrayUtil.reverse(ConvertUtil.convertToBooleans(number));
+        log.info("readConfirmNeedMark result is {}", confirmNeedMarkArray[bitIndex]);
+        return confirmNeedMarkArray[bitIndex];
+    }
+
+    /**
+     *  写无法注入药剂的方法
+     * @param bitIndex 点位的索引值
+     * @return
+     */
+    public Boolean writeUnableInject(int bitIndex) {
+        return write(READ_THE_REPOSITORY_01, WRITE_THE_STIRRING_TANK_01, bitIndex);
+    }
+
+    /**
+     *  写可以注入药剂的方法
+     * @param bitIndex 点位的索引值
+     * @return
+     */
+    public Boolean writeAbleInject(int bitIndex) {
+        return write(READ_THE_REPOSITORY_02, WRITE_THE_STIRRING_TANK_02, bitIndex);
+    }
+
+    /**
+     *  写任务运行
+     * @param bitIndex 点位的索引值
+     * @return
+     */
+    public Boolean writeTaskRun(int bitIndex) {
+        return write(READ_THE_REPOSITORY_03, WRITE_THE_STIRRING_TANK_03, bitIndex);
+    }
+
+    /**
+     *  写任务失败
+     * @param bitIndex 点位的索引值
+     * @return
+     */
+    public Boolean writeTaskError(int bitIndex) {
+        return write(READ_THE_REPOSITORY_04, WRITE_THE_STIRRING_TANK_04, bitIndex);
+    }
+
+    /**
+     *  写任务完成
+     * @param bitIndex 点位的索引值
+     * @return
+     */
+    public Boolean writeTaskEnd(int bitIndex) {
+        return write(READ_THE_REPOSITORY_05, WRITE_THE_STIRRING_TANK_05, bitIndex);
+    }
+
+    /**
+     * 读取并根据索引写入该点位的索引值
+     * @param bitIndex 点位的索引值
+     * @return
+     */
+    public Boolean write(STIR_TANK_COMMAND readTankCommand, STIR_TANK_COMMAND writeTankComand, int bitIndex) {
+        Number number = read1(readTankCommand.getSlaveId(), readTankCommand.getOffset());
+        boolean[] booleans = ArrayUtil.reverse(ConvertUtil.convertToBooleans(number));
+        booleans[bitIndex] = true;
+        int result = ConvertUtil.convertToInt(ArrayUtil.reverse(booleans));
+        log.info("comand slaveId is {}, comand offset is {}, write result is {}",
+                writeTankComand.getSlaveId(), writeTankComand.getOffset(), result);
+        return write(writeTankComand.getSlaveId(), writeTankComand.getOffset(), result);
+    }
+
     /**
      * 读碳酸钠搅拌槽液位
      *
@@ -1124,11 +1213,10 @@ public class StirringTankClient {
 
 
     /**
-     * 读的方法
+     * 读的方法 bad smell
      *
      * @param slaveId
      * @param offset
-     * @param len
      * @return
      */
     private Number read1(int slaveId, int offset) {

+ 50 - 0
warewms-hard/src/main/java/com/ruoyi/hard/xuankang/UnpackingMachineClient.java

@@ -1,13 +1,20 @@
 package com.ruoyi.hard.xuankang;
 
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.ArrayUtil;
+import com.alibaba.fastjson.JSONObject;
 import com.jwk.spring.boot.autoconfigure.ModbusTcpMasterTemplate;
 import com.jwk.spring.boot.constant.DATA_TYPE_WRAPPER;
 import com.jwk.spring.boot.modbus4j.ModbusMasterUtil;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ArrayUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Service;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import static com.ruoyi.hard.xuankang.UnpackingMachineClient.REGISTER_CODE.*;
 
 
@@ -29,6 +36,26 @@ public class UnpackingMachineClient {
     @Qualifier("modbusTcpMasterTemplateSecond")
     private ModbusTcpMasterTemplate modbusTcpMasterTemplateSecond;
 
+
+    //割刀机
+    private static final  Map<String, Map<String, Object>> onCutOffToolsMapper
+            = new HashMap<String, Map<String, Object>>(){
+        {
+            put("1", MapUtil.builder(new HashMap<String, Object>()).put("registerCode", REGISTER_CODE_1)
+                    .put("bitIndexes", new int[]{8, 9}).map());
+            put("2", MapUtil.builder(new HashMap<String, Object>()).put("registerCode", REGISTER_CODE_1)
+                    .put("bitIndexes", new int[]{0, 1}).map());
+            put("3", MapUtil.builder(new HashMap<String, Object>()).put("registerCode", REGISTER_CODE_2)
+                    .put("bitIndexes", new int[]{8, 9}).map());
+            put("4", MapUtil.builder(new HashMap<String, Object>()).put("registerCode", REGISTER_CODE_2)
+                    .put("bitIndexes", new int[]{0, 1}).map());
+            put("5", MapUtil.builder(new HashMap<String, Object>()).put("registerCode", REGISTER_CODE_3)
+                    .put("bitIndexes", new int[]{8, 9}).map());
+        }
+
+    };
+
+
     /**
      * 拆包机命令
      */
@@ -105,6 +132,29 @@ public class UnpackingMachineClient {
 
     }
 
+    /**
+     * 读拆包机割刀的运行状态
+     */
+    public Boolean[] readCutOffToolStatus(String lineId){
+        return readModuleStatus((UnpackingMachineClient.REGISTER_CODE)onCutOffToolsMapper.get(lineId).get("registerCode"),
+                (int[])onCutOffToolsMapper.get(lineId).get("bitIndexes"));
+    }
+
+    /**
+     * 读拆包机器各模组的状态
+     * @param registerCode 枚举常量
+     * @param bitIndexes 各部件的状态位对应索引
+     */
+    public Boolean[] readModuleStatus(REGISTER_CODE registerCode, int... bitIndexes) {
+        Number moduleInfo = read(registerCode.getSlaveId(), registerCode.getOffset());
+        log.info("current moduleBitInfo read value is {}", moduleInfo);
+        boolean[] moduleBitInfo = ArrayUtil.reverse(ConvertUtil.convertToBooleans(moduleInfo));
+        log.info("current moduleBitInfo is {}", JSONObject.toJSONString(moduleBitInfo));
+        Boolean[] boxedModuleBitInfo = ArrayUtils.toObject(moduleBitInfo);
+        return ArrayUtil.getAny(boxedModuleBitInfo, bitIndexes);
+    }
+
+
     /**
      * 读拆包机1# 2#各部件状态
      *

+ 4 - 0
warewms-hard/src/main/java/com/ruoyi/hard/xuankang/UnpackingMachineSubClient.java

@@ -249,4 +249,8 @@ public class UnpackingMachineSubClient {
         int i = ConvertUtil.convertToInt(booleans);
         return unpackingMachineClient.writeUnpackingRemoteInPlace01(i);
     }
+
+    public Boolean[] readCutOffToolStatus(String lineId) {
+        return  unpackingMachineClient.readCutOffToolStatus(lineId);
+    }
 }