From f97dee9338324bb5fd3d7f9f9007d3d4a45643cd Mon Sep 17 00:00:00 2001
From: youjie <272855983@qq.com>
Date: Fri, 7 Feb 2025 17:26:04 +0800
Subject: [PATCH] 悬架库出库

---
 ant-design-vue-jeecg/src/api/api.js                                                                                                |   2 ++
 ant-design-vue-jeecg/src/views/system/inventory/SimpleInventoryDetailList.vue                                                      |  26 ++++++++++++++++++++++++++
 ant-design-vue-jeecg/src/views/system/shipment/modules/CantaleverShipmentDetailModal.vue                                           | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 huaheng-wms-core/src/main/java/org/jeecg/modules/wms/api/wcs/service/LocationAllocationService.java                                |   2 +-
 huaheng-wms-core/src/main/java/org/jeecg/modules/wms/api/wcs/service/LocationAllocationServiceImpl.java                            |  25 ++++++++++++++++---------
 huaheng-wms-core/src/main/java/org/jeecg/modules/wms/api/wcs/service/WcsServiceImpl.java                                           |  47 ++++++++++++++++++++++++++++++++++++++++++++++-
 huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/controller/InventoryHeaderController.java           |  13 +++++++++++++
 huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/service/IInventoryDetailService.java                |   2 ++
 huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/service/IInventoryHeaderService.java                |   2 ++
 huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/service/impl/InventoryDetailServiceImpl.java        |  10 ++++++++++
 huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/service/impl/InventoryHeaderServiceImpl.java        | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 huaheng-wms-core/src/main/java/org/jeecg/modules/wms/shipment/shipmentCombination/service/impl/ShipmentCombinationServiceImpl.java |   2 ++
 huaheng-wms-core/src/main/java/org/jeecg/modules/wms/shipment/shipmentContainerHeader/entity/ShipmentContainerDetail.java          |   4 ++++
 huaheng-wms-core/src/main/java/org/jeecg/modules/wms/task/taskHeader/service/ITaskHeaderService.java                               |   8 ++++++++
 huaheng-wms-core/src/main/java/org/jeecg/modules/wms/task/taskHeader/service/impl/TaskHeaderServiceImpl.java                       |  52 ++++++++++++++++++++++++++++++++++++++--------------
 15 files changed, 477 insertions(+), 25 deletions(-)
 create mode 100644 ant-design-vue-jeecg/src/views/system/shipment/modules/CantaleverShipmentDetailModal.vue

diff --git a/ant-design-vue-jeecg/src/api/api.js b/ant-design-vue-jeecg/src/api/api.js
index f23df4d..c9965dc 100644
--- a/ant-design-vue-jeecg/src/api/api.js
+++ b/ant-design-vue-jeecg/src/api/api.js
@@ -281,6 +281,8 @@ export const quickReceipt = (params) => postAction('/task/taskHeader/quickReceip
 export const shipmentInventoryHeader = (params) => postAction('/inventory/inventoryHeader/shipmentInventoryHeader', params)
 //快速出库,批量快速出库存详情
 export const shipmentInventoryDetail = (params) => postAction('/inventory/inventoryHeader/shipmentInventoryDetail', params)
+//悬臂库快速出库,批量快速出库存详情
+export const cantaleverShipmentInventoryDetail = (params) => postAction('/inventory/inventoryHeader/cantaleverShipmentInventoryDetail', params)
 //平库快速出库,通过库存ID
 export const flatQuickShipment = (params) => postAction('/shipment/shipmentCombination/flatQuickShipment', params)
 //呼叫入库托盘
diff --git a/ant-design-vue-jeecg/src/views/system/inventory/SimpleInventoryDetailList.vue b/ant-design-vue-jeecg/src/views/system/inventory/SimpleInventoryDetailList.vue
index f29790a..044910f 100644
--- a/ant-design-vue-jeecg/src/views/system/inventory/SimpleInventoryDetailList.vue
+++ b/ant-design-vue-jeecg/src/views/system/inventory/SimpleInventoryDetailList.vue
@@ -157,6 +157,7 @@
       <a-button v-has="'inventoryHeader:flatReceipt'" @click="expressStorage()" type="primary">平库入库</a-button>
       <a-button v-has="'inventoryHeader:flatShipment'" @click="expressDelivery()" type="primary">平库出库</a-button>
       <a-button v-has="'taskHeader:transfer'" @click="createTransferTaskCantalever()" type="primary">悬臂库移库</a-button>
+      <a-button v-has="'inventoryHeader:quickShipmentInventoryHeader'" @click='cantaleverQuickShipment()' type='primary'>悬臂库出库</a-button>
       <!-- 高级查询区域 -->
       <j-super-query :fieldList="superFieldList" v-has="'inventoryDetail:superQuery'"
                      @handleSuperQuery="handleSuperQuery"/>
@@ -263,6 +264,7 @@
 
     <simple-inventory-detail-modal ref="modalForm" @ok="modalFormOk"></simple-inventory-detail-modal>
     <quick-shipment-detail-modal ref='quickShipmentDetailModal' @ok="modalFormOk"></quick-shipment-detail-modal>
+    <CantaleverShipmentDetailModal ref="cantaleverShipmentDetailModal" @ok="modalFormOk"></CantaleverShipmentDetailModal>
     <quality-inventory-detail-modal ref="qualityInventoryDetailModal" @ok="modalFormOk"></quality-inventory-detail-modal>
     <ExpressStorageModal ref="ExpressStorageModal" @ok="modalFormOk"></ExpressStorageModal>
     <ExpressDeliveryModal ref="ExpressDeliveryModal" @ok="modalFormOk"></ExpressDeliveryModal>
@@ -289,11 +291,13 @@ import TransferTaskCantaleverModal from "@views/system/task/modules/TransferTask
 import Vue from "vue";
 import {ACCESS_TOKEN} from "@/store/mutation-types";
 import store from "@/store";
+import CantaleverShipmentDetailModal from "@views/system/shipment/modules/CantaleverShipmentDetailModal.vue";
 
 export default {
   name: 'SimpleInventoryDetailList',
   mixins: [JeecgListMixin, mixinDevice],
   components: {
+    CantaleverShipmentDetailModal,
     ExpressStorageModal,
     ExpressDeliveryModal,
     QualityInventoryDetailModal,
@@ -789,6 +793,28 @@ export default {
       this.selectedRowKeys = selectedRowKeys;
       this.selectRecord = selectionRows;
     },
+    cantaleverQuickShipment() {
+      if (this.selectedRowKeys.length <= 0) {
+        this.$message.warning('请选择一条记录!');
+      } else {
+        let zoneCodes = this.selectRecord.map(row => row.zoneCode);
+        if (new Set(zoneCodes).size !== 1) {
+          this.$message.warning('所选数据非同库区');
+          return;
+        }
+        const isInList = this.selectRecord.some(row => {
+          if (row.zoneType != "L") {
+            return true
+          }
+        })
+        if(isInList) {
+          this.$message.warning('所选数据非立库区类型');
+          return;
+        }
+        this.$refs.cantaleverShipmentDetailModal.edit(this.selectRecord);
+        this.$refs.cantaleverShipmentDetailModal.title = '悬臂库出库';
+      }
+    },
     quickShipment() {
       if (this.selectedRowKeys.length <= 0) {
         this.$message.warning('请选择一条记录!');
diff --git a/ant-design-vue-jeecg/src/views/system/shipment/modules/CantaleverShipmentDetailModal.vue b/ant-design-vue-jeecg/src/views/system/shipment/modules/CantaleverShipmentDetailModal.vue
new file mode 100644
index 0000000..fb9ce9a
--- /dev/null
+++ b/ant-design-vue-jeecg/src/views/system/shipment/modules/CantaleverShipmentDetailModal.vue
@@ -0,0 +1,205 @@
+<template>
+  <j-modal
+    :title="title"
+    :width="width"
+    :visible="visible"
+    :confirmLoading="confirmLoading"
+    switchFullscreen
+    @ok="handleOk"
+    @cancel="handleCancel"
+    cancelText="关闭"
+  >
+    <a-spin :spinning="confirmLoading">
+      <a-form-model ref="form" :model="model" :rules="validatorRules">
+        <a-row>
+          <a-col :span="24">
+            <a-form-model-item label="出库口" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="outPortCode">
+              <a-select
+                show-search
+                placeholder="请选择出库口"
+                option-filter-prop="children"
+                v-model="model.outPortCode"
+              >
+                <a-select-option v-for="item in portList" :key="item.name" :value="item.code">
+                  {{ item.name }}
+                </a-select-option>
+              </a-select>
+            </a-form-model-item>
+          </a-col>
+        </a-row>
+      </a-form-model>
+    </a-spin>
+    <a-table ref="table" rowKey="id" size="middle" :columns="columns" :dataSource="dataSource" :pagination="false">
+      <span slot="action" slot-scope="text, record">
+        <a-input-number placeholder="" v-model="record.shipmentQty" :value="text" />
+      </span>
+
+
+<!--      <span slot="inventoryStatus" slot-scope="inventoryStatus">-->
+<!--          <a-tag :key="inventoryStatus" color="blue" :color="getStatusColor(inventoryStatus)">-->
+<!--            {{ solutionInvStatus(inventoryStatus) }}-->
+<!--          </a-tag>-->
+<!--        </span>-->
+
+    </a-table>
+  </j-modal>
+</template>
+
+<script>
+import {
+  cantaleverShipmentInventoryDetail,
+  getZoneList,
+  selectOutPort,
+  selectPickPort,
+  shipmentInventoryDetail
+} from '@/api/api'
+import {getAction} from "@api/manage";
+
+export default {
+  name: 'CantaleverShipmentDetailModal',
+  components: {},
+  data() {
+    return {
+      title: '操作',
+      width: 800,
+      portList: [],
+      inventoryDetailList: [],
+      dataSource: [],
+      querySource: {},
+      visible: false,
+      model: {},
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 5 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      },
+      columns: [
+        {
+          title: '容器编码',
+          dataIndex: 'containerCode',
+          align: 'center',
+        },
+        {
+          title: '物料编码',
+          dataIndex: 'materialCode',
+          align: 'center',
+          width: 124
+        },
+        {
+          title: '物料名称',
+          dataIndex: 'materialName',
+          align: 'center',
+          width: 96
+        },
+        // {
+        //   title: '库存状态',
+        //   align: 'center',
+        //   dataIndex: 'inventoryStatus_dictText',
+        //   scopedSlots: {customRender: 'inventoryStatus_dictText'}
+        // },
+        {
+          title: '批次',
+          dataIndex: 'batch',
+          align: 'center'
+        },
+        {
+          title: '位置',
+          dataIndex: 'position',
+          align: 'center'
+        },
+        {
+          title: '库存数量',
+          dataIndex: 'qty',
+          align: 'center',
+          width: 80
+        },
+        {
+          title: '出库数量',
+          dataIndex: 'shipmentQty',
+          align: 'center',
+          key: 'action',
+          scopedSlots: { customRender: 'action' }
+        },
+      ],
+      url: {
+        pageByMainIds: "/inventory/inventoryDetail/pageByMainIds",
+      },
+      // 选择用户查询条件配置
+      selectUserQueryConfig: [],
+      confirmLoading: false,
+      validatorRules: {
+        outPortCode: [{ required: true, message: '请选择出库口!' }]
+      }
+    }
+  },
+  created() {
+    //备份model原始值
+    this.modelDefault = JSON.parse(JSON.stringify(this.model))
+  },
+  methods: {
+    add() {
+      this.edit(this.modelDefault)
+    },
+    edit(record) {
+      this.visible = true
+      this.model.containerCode = record[0].containerCode
+      this.inventoryDetailList = record
+      this.getPortList()
+      this.searchInventoryDetailList();
+    },
+    close() {
+      this.$emit('close')
+      this.visible = false
+      this.$refs.form.clearValidate()
+    },
+    getPortList() {
+      this.querySource.containerCode = this.model.containerCode
+      selectOutPort(this.querySource).then(res => {
+        if (res.success) {
+          this.portList = res.result
+          this.visible = true
+          if (this.portList.length == 1) {
+            this.model.outPortCode = this.portList[0].code;
+          }
+        }
+      })
+    },
+    searchInventoryDetailList() {
+      let params = {
+        inventoryHeaderIds:""
+      };
+      this.inventoryDetailList.forEach(x=>{
+        params.inventoryHeaderIds+=  + x.inventoryHeaderId + ","
+      })
+      getAction(this.url.pageByMainIds, params).then((res) => {
+        this.dataSource = res.result.records
+        this.inventoryDetailList = res.result.records
+      })
+    },
+    handleOk() {
+      if (this.model.outPortCode === '') {
+        this.$message.warning('请选择出库口')
+      }
+      this.inventoryDetailList.forEach(x => {
+        x['toPortCode'] = this.model.outPortCode
+      })
+      cantaleverShipmentInventoryDetail(this.inventoryDetailList).then(res => {
+        if (res.success) {
+          this.$message.success(res.message)
+          this.$emit('ok')
+        } else {
+          this.$message.error(res.message)
+        }
+      })
+      this.$emit('ok', this.model.outPortCode)
+      this.close()
+    },
+    handleCancel() {
+      this.close()
+    }
+  }
+}
+</script>
\ No newline at end of file
diff --git a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/api/wcs/service/LocationAllocationService.java b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/api/wcs/service/LocationAllocationService.java
index 8e3e9e6..6e03fc1 100644
--- a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/api/wcs/service/LocationAllocationService.java
+++ b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/api/wcs/service/LocationAllocationService.java
@@ -26,7 +26,7 @@ public interface LocationAllocationService {
      * 单伸位库位分配
      */
     String singleRkCantalever(String zoneCode, List<Integer> roadWays, int high, String warehouseCode, List<String> locationTypeCodeList, String materialAreaCode,
-                    String materialCode);
+                    List<String> materialCodeList);
 
     /**
      * 获取可用巷道
diff --git a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/api/wcs/service/LocationAllocationServiceImpl.java b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/api/wcs/service/LocationAllocationServiceImpl.java
index 2f7d958..169fce5 100644
--- a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/api/wcs/service/LocationAllocationServiceImpl.java
+++ b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/api/wcs/service/LocationAllocationServiceImpl.java
@@ -105,7 +105,9 @@ public class LocationAllocationServiceImpl implements LocationAllocationService 
                     bypass);
             case QuantityConstant.SINGLE_FORK:
                 if (zoneCode.equals(QuantityConstant.ZONE_B)) {
-                    return locationAllocationService.singleRkCantalever(zoneCode, raodWays, high, warehouseCode, mergelocationTypeCodeList, materialAreaCode, materialCode);
+                    List<String> materialCodeList = new ArrayList<>();
+                    materialCodeList.add(materialCode);
+                    return locationAllocationService.singleRkCantalever(zoneCode, raodWays, high, warehouseCode, mergelocationTypeCodeList, materialAreaCode, materialCodeList);
                 } else {
                     return locationAllocationService.singleRk(zoneCode, raodWays, high, warehouseCode, mergelocationTypeCodeList, materialAreaCode, materialCode);
                 }
@@ -282,21 +284,26 @@ public class LocationAllocationServiceImpl implements LocationAllocationService 
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public String singleRkCantalever(String zoneCode, List<Integer> roadWays, int high, String warehouseCode, List<String> locationTypeCodeList, String materialAreaCode, String materialCode) {
+    public String singleRkCantalever(String zoneCode, List<Integer> roadWays, int high, String warehouseCode, List<String> locationTypeCodeList, String materialAreaCode, List<String> materialCodeList) {
         if (CollectionUtils.isEmpty(roadWays)) {
             roadWays = locationService.getRoadWayByZoneCode(zoneCode, warehouseCode);
         }
         List<Integer> removeRoadWays = new ArrayList<>();
-        if (StringUtils.isEmpty(materialCode)) {
+        if (materialCodeList == null) {
             throw new JeecgBootException("分配库位时, 入库物料信息为空");
         }
-        Material material = materialService.getMaterialByCode(materialCode);
-        if (material == null) {
-            throw new JeecgBootException("分配库位时, 没有找到入库物料信息" + materialCode);
+        int thickness = 0;
+        String materialCode = null;
+        for (int i=0; i < materialCodeList.size(); i++) {
+            materialCode = materialCodeList.get(i);
+            Material material = materialService.getMaterialByCode(materialCode);
+            if (material == null) {
+                throw new JeecgBootException("分配库位时, 没有找到入库物料信息" + materialCode);
+            }
+            int materialThickness = material.getThickness();
+            int materialGap = material.getGap();
+            thickness = thickness + materialThickness + materialGap;
         }
-        int materialThickness = material.getThickness();
-        int materialGap = material.getGap();
-        int thickness = materialThickness + materialGap;
         // 寻找可用巷道,空闲的空库位低于设定值,那么这个巷道就不能用来分配库位
         for (Integer roadWay : roadWays) {
             LambdaQueryWrapper<Location> locationLambdaQueryWrapper = Wrappers.lambdaQuery();
diff --git a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/api/wcs/service/WcsServiceImpl.java b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/api/wcs/service/WcsServiceImpl.java
index 18895e5..0cd2dab 100644
--- a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/api/wcs/service/WcsServiceImpl.java
+++ b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/api/wcs/service/WcsServiceImpl.java
@@ -57,6 +57,7 @@ import javax.annotation.Resource;
 import java.math.BigDecimal;
 import java.net.SocketException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -475,7 +476,7 @@ public class WcsServiceImpl implements WcsService {
         if (!direction) {
             // 出库性质的任务圆库位不能为空
             if (StringUtils.isEmpty(fromLocationCode)) {
-                return Result.error("任务下发 ,起始库位为空");
+                return Result.error("任务下发, 起始库位为空");
             }
             int rowFlag = fromLocation.getRowFlag();
             if (rowFlag == QuantityConstant.ROW_OUT) {
@@ -529,6 +530,50 @@ public class WcsServiceImpl implements WcsService {
             }
         }
 
+        if (!direction) {
+            String fromZoneCode = fromLocation.getZoneCode();
+            if (fromZoneCode.equals(QuantityConstant.ZONE_B)) {
+                List<TaskDetail> taskDetailList = taskDetailService.getTaskDetailListByTaskId(taskHeader.getId());
+                if (CollectionUtils.isNotEmpty(taskDetailList)) {
+                    List<Integer> positionList = taskDetailList.stream().map(TaskDetail::getPosition).collect(Collectors.toList());
+                    Integer minTaskPosition = Collections.min(positionList);
+                    List<InventoryDetail> inventoryDetailList = inventoryDetailService.getInventoryDetailListByLocationCodeAndNotPosition(fromLocationCode, positionList, warehouseCode);
+                    List<Integer> inventoryPositionList = inventoryDetailList.stream().map(InventoryDetail::getPosition).collect(Collectors.toList());
+                    Integer minInventoryPosition = Collections.min(inventoryPositionList);
+                    if (minTaskPosition < minInventoryPosition) {
+                        TaskHeader unCompleteTaskHeader = taskHeaderService.getUnCompleteTransferTaskByFromLocationCode(fromLocationCode, warehouseCode);
+                        if (unCompleteTaskHeader != null) {
+                            preTaskNo = unCompleteTaskHeader.getId();
+                            boolean success = taskHeaderService.updatePreTaskNoById(preTaskNo, taskHeader.getId());
+                            if (!success) {
+                                throw new JeecgBootException("任务下发, 更新任务前置任务号失败");
+                            }
+                        } else {
+                            List<String> locationTypeCodeList = new ArrayList<>();
+                            locationTypeCodeList.add(fromLocation.getLocationTypeCode());
+                            List<Integer> roadWays = new ArrayList<>();
+                            roadWays.add(fromLocation.getRoadWay());
+                            List<String> materialCodeList = inventoryDetailList.stream().map(InventoryDetail::getMaterialCode).collect(Collectors.toList());
+                            String locationCode = locationAllocationService.singleRkCantalever( fromZoneCode, roadWays, 0, warehouseCode,
+                                    locationTypeCodeList, null, materialCodeList);
+                            Result<TaskHeader> result = taskHeaderService.createTransferTaskCantalever(inventoryDetailList, locationCode, warehouseCode);
+                            if (!result.isSuccess()) {
+                                throw new JeecgBootException("任务下发 " + result.getMessage());
+                            }
+                            preTaskNo = result.getResult().getId();
+                            taskHeader.setPreTaskNo(preTaskNo);
+                            boolean success = taskHeaderService.updatePreTaskNoById(preTaskNo, taskHeader.getId());
+                            if (!success) {
+                                throw new JeecgBootException("任务下发, 更新任务状态失败");
+                            }
+                            return Result.error("任务下发, 先执行移库任务");
+                        }
+
+                    }
+                }
+            }
+        }
+
         // 下发任务
         WcsTask wcsTask = new WcsTask();
         wcsTask.setTaskNo(taskHeader.getId().toString());
diff --git a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/controller/InventoryHeaderController.java b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/controller/InventoryHeaderController.java
index 83ab271..e5bc1e7 100644
--- a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/controller/InventoryHeaderController.java
+++ b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/controller/InventoryHeaderController.java
@@ -420,6 +420,19 @@ public class InventoryHeaderController extends JeecgController<InventoryHeader, 
         return inventoryHeaderService.shipmentInventoryDetail(inventoryDetailList, warehouseCode);
     }
 
+    @AutoLog(value = "库存头-批量出库存详情", operateType = 4)
+    @ApiOperation(value = "批量出库存详情", notes = "批量出库存详情")
+    @ApiLogger(apiName = "批量出库存详情")
+    @PostMapping("/cantaleverShipmentInventoryDetail")
+    public Result cantaleverShipmentInventoryDetail(@RequestBody List<InventoryDetail> inventoryDetailList, HttpServletRequest req) {
+        if (StringUtils.isEmpty(inventoryDetailList)) {
+            return Result.error("库存明细为空");
+        }
+        String warehouseCode = HuahengJwtUtil.getWarehouseCodeByToken(req);
+        return inventoryHeaderService.cantaleverShipmentInventoryDetail(inventoryDetailList, warehouseCode);
+    }
+
+
     @AutoLog(value = "批量出库存详情", operateType = 4)
     @ApiOperation(value = "批量出库存详情", notes = "批量出库存详情")
     @PostMapping("/decuceInventoryDetail")
diff --git a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/service/IInventoryDetailService.java b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/service/IInventoryDetailService.java
index 818d7e7..62d9f0c 100644
--- a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/service/IInventoryDetailService.java
+++ b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/service/IInventoryDetailService.java
@@ -35,6 +35,8 @@ public interface IInventoryDetailService extends IService<InventoryDetail> {
 
     List<InventoryDetail> getInventoryDetailListByLocationCode(String locationCode, String warehouseCode);
 
+    List<InventoryDetail> getInventoryDetailListByLocationCodeAndNotPosition(String locationCode, List<Integer> positionList,String warehouseCode);
+
     List<InventoryDetail> getInventoryDetailListByMaterialCode(String materialCode, String warehouseCode);
 
     List<InventoryDetail> getInventoryDetailListByMaterialCodeAndZoneCode(String materialCode, String zoneCode, String warehouseCode);
diff --git a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/service/IInventoryHeaderService.java b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/service/IInventoryHeaderService.java
index b447c21..a2b14e8 100644
--- a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/service/IInventoryHeaderService.java
+++ b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/service/IInventoryHeaderService.java
@@ -50,6 +50,8 @@ public interface IInventoryHeaderService extends IService<InventoryHeader> {
 
     Result shipmentInventoryDetail(List<InventoryDetail> inventoryDetailList, String warehouseCode);
 
+    Result cantaleverShipmentInventoryDetail(List<InventoryDetail> inventoryDetailList, String warehouseCode);
+
     Result decuceInventoryDetail(List<InventoryDetail> inventoryDetailList, String warehouseCode);
 
     boolean updateInventory(String containerCode, String locationCode, String warehouseCode);
diff --git a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/service/impl/InventoryDetailServiceImpl.java b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/service/impl/InventoryDetailServiceImpl.java
index 4ef6a4c..ba96b8a 100644
--- a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/service/impl/InventoryDetailServiceImpl.java
+++ b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/service/impl/InventoryDetailServiceImpl.java
@@ -166,6 +166,16 @@ public class InventoryDetailServiceImpl extends ServiceImpl<InventoryDetailMappe
     }
 
     @Override
+    public List<InventoryDetail> getInventoryDetailListByLocationCodeAndNotPosition(String locationCode, List<Integer> positionList, String warehouseCode) {
+        LambdaQueryWrapper<InventoryDetail> inventoryDetailLambdaQueryWrapper = Wrappers.lambdaQuery();
+        inventoryDetailLambdaQueryWrapper.eq(InventoryDetail::getLocationCode, locationCode).eq(InventoryDetail::getWarehouseCode, warehouseCode)
+                .notIn(InventoryDetail::getPosition, positionList)
+                .eq(InventoryDetail::getEnable, QuantityConstant.INVENTORY_DETAIL_STATUS_ENABLE);
+        List<InventoryDetail> inventoryDetailList = list(inventoryDetailLambdaQueryWrapper);
+        return inventoryDetailList;
+    }
+
+    @Override
     public List<InventoryDetail> getInventoryDetailListByMaterialCode(String materialCode, String warehouseCode) {
         LambdaQueryWrapper<InventoryDetail> inventoryDetailLambdaQueryWrapper = Wrappers.lambdaQuery();
         inventoryDetailLambdaQueryWrapper.eq(InventoryDetail::getMaterialCode, materialCode).eq(InventoryDetail::getWarehouseCode, warehouseCode);
diff --git a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/service/impl/InventoryHeaderServiceImpl.java b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/service/impl/InventoryHeaderServiceImpl.java
index 6c52839..d80132b 100644
--- a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/service/impl/InventoryHeaderServiceImpl.java
+++ b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/inventory/inventoryHeader/service/impl/InventoryHeaderServiceImpl.java
@@ -411,6 +411,108 @@ public class InventoryHeaderServiceImpl extends ServiceImpl<InventoryHeaderMappe
         return Result.OK("批量快速出库成功");
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Result cantaleverShipmentInventoryDetail(List<InventoryDetail> inventoryDetailList, String warehouseCode) {
+        if (StringUtils.isEmpty(inventoryDetailList)) {
+            return Result.error("批量快速出库,所选库存详情为空");
+        }
+        String toPortCode = inventoryDetailList.get(0).getToPortCode();
+        if (StringUtils.isEmpty(toPortCode)) {
+            return Result.error("批量快速出库,出库站台编码为空");
+        }
+        String zoneCode = inventoryDetailList.get(0).getZoneCode();
+        inventoryDetailList =
+                inventoryDetailList.stream().filter((item) -> item.getContainerStatus().equals(QuantityConstant.STATUS_CONTAINER_EMPTY)).collect(Collectors.toList());
+        inventoryDetailList = inventoryDetailList.stream().filter((item) -> item.getShipmentQty() != null).collect(Collectors.toList());
+        if (StringUtils.isEmpty(inventoryDetailList)) {
+            return Result.error("批量快速出库, 排除锁定库存后没有可出库存详情");
+        }
+        if (inventoryDetailList.size() != 1) {
+            return Result.error("批量快速出库, 可出库存详情数量只能为1");
+        }
+        String zoneType = null;
+        if (StringUtils.isNotEmpty(zoneCode)) {
+            Zone zone = zoneService.getZoneByCode(zoneCode, warehouseCode);
+            if (zone == null) {
+                return Result.error("出库单下发, 没有找到库区");
+            }
+            zoneType = zone.getType();
+        }
+        String companyCode = inventoryDetailList.get(0).getCompanyCode();
+        ShipmentHeader shipmentHeader = new ShipmentHeader();
+        shipmentHeader.setWarehouseCode(warehouseCode);
+        shipmentHeader.setCompanyCode(companyCode);
+        shipmentHeader.setZoneCode(zoneCode);
+        shipmentHeader.setZoneType(zoneType);
+        shipmentHeader.setType(QuantityConstant.SHIPMENT_BILL_TYPE_QTC);
+        shipmentHeader.setRemark("快速出库");
+        Result result = shipmentHeaderService.saveShipmentHeader(shipmentHeader);
+        if (!result.isSuccess()) {
+            throw new JeecgBootException("批量快速出库,创建出库单失败:".concat(result.getMessage()));
+        }
+
+        List<ShipmentDetail> shipmentDetailList = new ArrayList<>();
+        for (InventoryDetail inventoryDetail : inventoryDetailList) {
+            ShipmentDetail shipmentDetail = new ShipmentDetail();
+            shipmentDetail.setShipmentId(shipmentHeader.getId());
+            shipmentDetail.setMaterialCode(inventoryDetail.getMaterialCode());
+            shipmentDetail.setInventoryStatus(inventoryDetail.getInventoryStatus());
+            shipmentDetail.setZoneCode(inventoryDetail.getZoneCode());
+            shipmentDetail.setQty(inventoryDetail.getShipmentQty());
+            shipmentDetail.setBatch(inventoryDetail.getBatch());
+            result = shipmentDetailService.saveShipmentDetail(shipmentDetail);
+            if (!result.isSuccess()) {
+                throw new JeecgBootException("批量快速出库,创建出库详情失败:".concat(result.getMessage()));
+            }
+            shipmentDetail = shipmentDetailService.getById(shipmentDetail.getId());
+            shipmentDetailList.add(shipmentDetail);
+        }
+
+        for (int i = 0; i < inventoryDetailList.size(); i++) {
+            InventoryDetail inventoryDetail = inventoryDetailList.get(i);
+            ShipmentDetail shipmentDetail = shipmentDetailList.get(i);
+            CombinationModel combinationModel = new CombinationModel();
+            combinationModel.setInventoryDetail(inventoryDetail);
+            combinationModel.setShipmentDetail(shipmentDetail);
+            combinationModel.setShipQty(inventoryDetail.getShipmentQty());
+            result = shipmentCombinationService.combination(combinationModel);
+            if (!result.isSuccess()) {
+                throw new JeecgBootException("批量快速出库,配盘失败:".concat(result.getMessage()));
+            }
+        }
+
+        List<ShipmentContainerDetail> shipmentContainerDetailList =
+                shipmentContainerDetailService.getShipmentContainerDetailListByShipmentCode(shipmentHeader.getCode());
+        if (StringUtils.isEmpty(shipmentContainerDetailList)) {
+            throw new JeecgBootException("批量快速出库,根据出库单没有找到配盘详情");
+        }
+
+        List<Integer> shipmentContainerHeaderIdList =
+                shipmentContainerDetailList.stream().map(ShipmentContainerDetail::getShipmentContainerId).distinct().collect(Collectors.toList());
+        long shipmentOrder = System.currentTimeMillis();
+        int sequenceNumber = shipmentContainerHeaderIdList.size();
+        int sequence = 0;
+        for (int shipmentContainerId : shipmentContainerHeaderIdList) {
+            sequence++;
+            ShipmentContainerHeader shipmentContainerHeader = shipmentContainerHeaderService.getById(shipmentContainerId);
+            if (shipmentContainerHeader == null) {
+                throw new JeecgBootException("批量快速出库,没有找到出库表头:" + shipmentContainerId);
+            }
+            shipmentContainerHeader.setToPort(toPortCode);
+            boolean success = shipmentContainerHeaderService.updateById(shipmentContainerHeader);
+            if (!success) {
+                throw new JeecgBootException("批量快速出库,更新出库组盘头失败");
+            }
+            result = shipmentCombinationService.createShipmentTask(shipmentContainerHeader, QuantityConstant.TASK_TYPE_WHOLESHIPMENT, warehouseCode, shipmentOrder, sequence, sequenceNumber);
+            if (!result.isSuccess()) {
+                throw new JeecgBootException(result.getMessage());
+            }
+        }
+
+        return Result.OK("批量快速出库成功");
+    }
+
     /**
      * 批量出库存详情
      * @param  inventoryDetailList
diff --git a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/shipment/shipmentCombination/service/impl/ShipmentCombinationServiceImpl.java b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/shipment/shipmentCombination/service/impl/ShipmentCombinationServiceImpl.java
index abb37b2..d9d4125 100644
--- a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/shipment/shipmentCombination/service/impl/ShipmentCombinationServiceImpl.java
+++ b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/shipment/shipmentCombination/service/impl/ShipmentCombinationServiceImpl.java
@@ -914,6 +914,7 @@ public class ShipmentCombinationServiceImpl implements IShipmentCombinationServi
             shipmentContainerDetail.setMaterialName(shipmentDetail.getMaterialName());
             shipmentContainerDetail.setMaterialSpec(shipmentDetail.getMaterialSpec());
             shipmentContainerDetail.setMaterialUnit(shipmentDetail.getMaterialUnit());
+            shipmentContainerDetail.setPosition(inventoryDetail.getPosition());
             shipmentContainerDetail.setQty(shipmentQty);
             shipmentContainerDetail.setBatch(shipmentDetail.getBatch());
             shipmentContainerDetail.setLot(shipmentDetail.getLot());
@@ -1616,6 +1617,7 @@ public class ShipmentCombinationServiceImpl implements IShipmentCombinationServi
             taskDetail.setMaterialSpec(shipmentContainerDetail.getMaterialSpec());
             taskDetail.setMaterialName(shipmentContainerDetail.getMaterialName());
             taskDetail.setMaterialUnit(shipmentContainerDetail.getMaterialUnit());
+            taskDetail.setPosition(shipmentContainerDetail.getPosition());
             taskDetail.setQty(shipmentContainerDetail.getQty());
             taskDetailList.add(taskDetail);
         }
diff --git a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/shipment/shipmentContainerHeader/entity/ShipmentContainerDetail.java b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/shipment/shipmentContainerHeader/entity/ShipmentContainerDetail.java
index 7cb0504..72d3da7 100644
--- a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/shipment/shipmentContainerHeader/entity/ShipmentContainerDetail.java
+++ b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/shipment/shipmentContainerHeader/entity/ShipmentContainerDetail.java
@@ -112,6 +112,10 @@ public class ShipmentContainerDetail implements Serializable {
     @Excel(name = "序列号", width = 15)
     @ApiModelProperty(value = "序列号")
     private String sn;
+    /** 位置 */
+    @Excel(name = "位置", width = 15)
+    @ApiModelProperty(value = "位置")
+    private Integer position;
     /** 备用字段1 */
     @Excel(name = "备用字段1", width = 15)
     @ApiModelProperty(value = "备用字段1")
diff --git a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/task/taskHeader/service/ITaskHeaderService.java b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/task/taskHeader/service/ITaskHeaderService.java
index b8ea396..618ba4f 100644
--- a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/task/taskHeader/service/ITaskHeaderService.java
+++ b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/task/taskHeader/service/ITaskHeaderService.java
@@ -65,6 +65,14 @@ public interface ITaskHeaderService extends IService<TaskHeader> {
     TaskHeader getUnCompleteTaskByToLocationCode(String toLocationCode, String warehouseCode);
 
     /**
+     * 通过目标库位编码,获取任务信息
+     * @param  toLocationCode
+     * @param  warehouseCode
+     * @return
+     */
+    TaskHeader getUnCompleteTransferTaskByFromLocationCode(String toLocationCode, String warehouseCode);
+
+    /**
      * 通过库位编码,获取任务信息
      * @param  locationCode
      * @param  warehouseCode
diff --git a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/task/taskHeader/service/impl/TaskHeaderServiceImpl.java b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/task/taskHeader/service/impl/TaskHeaderServiceImpl.java
index f256ba3..44e2b66 100644
--- a/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/task/taskHeader/service/impl/TaskHeaderServiceImpl.java
+++ b/huaheng-wms-core/src/main/java/org/jeecg/modules/wms/task/taskHeader/service/impl/TaskHeaderServiceImpl.java
@@ -1015,6 +1015,16 @@ public class TaskHeaderServiceImpl extends ServiceImpl<TaskHeaderMapper, TaskHea
     }
 
     @Override
+    public TaskHeader getUnCompleteTransferTaskByFromLocationCode(String fromLocationCode, String warehouseCode) {
+        LambdaQueryWrapper<TaskHeader> taskHeaderLambdaQueryWrapper = Wrappers.lambdaQuery();
+        taskHeaderLambdaQueryWrapper.eq(TaskHeader::getFromLocationCode, fromLocationCode).eq(TaskHeader::getTaskType, QuantityConstant.TASK_TYPE_TRANSFER).
+                eq(TaskHeader::getWarehouseCode, warehouseCode).lt(TaskHeader::getStatus,
+                QuantityConstant.TASK_STATUS_COMPLETED);
+        TaskHeader taskHeader = taskHeaderService.getOne(taskHeaderLambdaQueryWrapper);
+        return taskHeader;
+    }
+
+    @Override
     public TaskHeader getUnCompleteTaskByLocationCode(String locationCode, String warehouseCode) {
         TaskHeader taskHeader = getUnCompleteTaskByFromLocationCode(locationCode, warehouseCode);
         if (taskHeader == null) {
@@ -1556,7 +1566,11 @@ public class TaskHeaderServiceImpl extends ServiceImpl<TaskHeaderMapper, TaskHea
             return Result.error("创建移库任务失败,起始库位:" + fromLocationCode + "和目标库位:" + toLocationCode + "是同一个");
         }
         String containerCode = fromLocation.getContainerCode();
-
+        TaskHeader unComleteTask = taskHeaderService.getUnCompleteTaskByContainerCode(containerCode, warehouseCode);
+        if (unComleteTask != null) {
+            Container container = containerService.createLSContainer(warehouseCode);
+            containerCode = container.getCode();
+        }
         List<InventoryDetail> toInventoryDetailList = inventoryDetailService.getInventoryDetailListByLocationCode(toLocationCode, warehouseCode);
         List<InventoryDetail> totalInventoryDetailList = new ArrayList<>();
         if (CollectionUtils.isNotEmpty(toInventoryDetailList)) {
@@ -1573,9 +1587,9 @@ public class TaskHeaderServiceImpl extends ServiceImpl<TaskHeaderMapper, TaskHea
             return Result.error("创建移库任务时,起始库位:" + fromLocationCode + "存在入库组盘,不能移库");
         }
         // 校验出库组盘
-        if (shipmentContainerHeaderService.havaUnCompleteCombineByLocationCode(fromLocationCode, warehouseCode)) {
-            return Result.error("创建移库任务时,起始库位:" + fromLocationCode + "存在出库组盘,不能移库");
-        }
+//        if (shipmentContainerHeaderService.havaUnCompleteCombineByLocationCode(fromLocationCode, warehouseCode)) {
+//            return Result.error("创建移库任务时,起始库位:" + fromLocationCode + "存在出库组盘,不能移库");
+//        }
 
         // 校验入库组盘
         if (receiptContainerHeaderService.havaUnCompleteCombineByLocationCode(toLocationCode, warehouseCode)) {
@@ -2622,23 +2636,29 @@ public class TaskHeaderServiceImpl extends ServiceImpl<TaskHeaderMapper, TaskHea
         if (container == null) {
             return Result.error("创建分拣任务时, 没有找到托盘" + containerCode);
         }
-        if (!container.getStatus().equals(QuantityConstant.STATUS_CONTAINER_EMPTY)) {
-            return Result.error("创建分拣任务时, 托盘状态并非空闲状态");
-        }
-        if (StringUtils.isEmpty(container.getLocationCode())) {
-            return Result.error("创建分拣任务时, 容器不在库位" + container.getLocationCode() + "上");
-        }
         Location fromLocation = locationService.getLocationByCode(fromLocationCode, warehouseCode);
         if (fromLocation == null) {
             return Result.error("创建分拣任务时, 起始库位为空");
         }
+        zoneCode = fromLocation.getZoneCode();
+        if (!container.getStatus().equals(QuantityConstant.STATUS_CONTAINER_EMPTY)) {
+            if (!zoneCode.equals(QuantityConstant.ZONE_B)) {
+                return Result.error("创建分拣任务时, 托盘状态并非空闲状态");
+            }
+        }
+        if (StringUtils.isEmpty(container.getLocationCode())) {
+            if (!zoneCode.equals(QuantityConstant.ZONE_B)) {
+                return Result.error("创建分拣任务时, 容器不在库位" + container.getLocationCode() + "上");
+            }
+        }
         if (StringUtils.isEmpty(fromLocation.getContainerCode())) {
             return Result.error("创建分拣任务时," + fromLocationCode + "上已存在容器" + fromLocation.getContainerCode());
         }
         if (!QuantityConstant.STATUS_LOCATION_EMPTY.equals(fromLocation.getStatus())) {
-            return Result.error("创建分拣任务时, 起始库位非空闲");
+            if (!zoneCode.equals(QuantityConstant.ZONE_B)) {
+                return Result.error("创建分拣任务时, 起始库位非空闲");
+            }
         }
-        zoneCode = fromLocation.getZoneCode();
         taskLockEntity.setZoneCode(zoneCode);
         if (StringUtils.isNotEmpty(toLocationCode) && !fromLocationCode.equals(toLocationCode)) {
             Location toLocation = locationService.getLocationByCode(toLocationCode, warehouseCode);
@@ -2657,11 +2677,15 @@ public class TaskHeaderServiceImpl extends ServiceImpl<TaskHeaderMapper, TaskHea
         }
         success = containerService.updateStatus(containerCode, QuantityConstant.STATUS_CONTAINER_LOCK, warehouseCode);
         if (!success) {
-            throw new JeecgBootException("创建分拣任务时,更新容器状态失败");
+            if (!zoneCode.equals(QuantityConstant.ZONE_B)) {
+                throw new JeecgBootException("创建分拣任务时,更新容器状态失败");
+            }
         }
         success = locationService.updateStatus(fromLocationCode, QuantityConstant.STATUS_LOCATION_LOCK, warehouseCode);
         if (!success) {
-            throw new JeecgBootException("创建分拣任务时,更新库位状态失败");
+            if (!zoneCode.equals(QuantityConstant.ZONE_B)) {
+                throw new JeecgBootException("创建分拣任务时,更新库位状态失败");
+            }
         }
         if (StringUtils.isNotEmpty(toLocationCode)) {
             if (!fromLocationCode.equals(toLocationCode)) {
--
libgit2 0.22.2