ShipmentTaskService.java 21.1 KB
package com.huaheng.pc.task.taskHeader.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.huaheng.common.constant.QuantityConstant;
import com.huaheng.common.exception.service.ServiceException;
import com.huaheng.common.utils.StringUtils;
import com.huaheng.common.utils.security.ShiroUtils;
import com.huaheng.framework.web.domain.AjaxResult;
import com.huaheng.pc.config.container.domain.Container;
import com.huaheng.pc.config.container.service.ContainerService;
import com.huaheng.pc.config.location.domain.Location;
import com.huaheng.pc.config.location.service.LocationService;
import com.huaheng.pc.config.material.domain.Material;
import com.huaheng.pc.config.materialWarnning.domain.MaterialWarning;
import com.huaheng.pc.config.materialWarnning.service.IMaterialWarningService;
import com.huaheng.pc.inventory.inventoryDetail.domain.InventoryDetail;
import com.huaheng.pc.inventory.inventoryDetail.service.InventoryDetailService;
import com.huaheng.pc.inventory.inventoryHeader.domain.InventoryHeader;
import com.huaheng.pc.inventory.inventoryHeader.service.InventoryHeaderService;
import com.huaheng.pc.inventory.inventoryTransaction.domain.InventoryTransaction;
import com.huaheng.pc.inventory.inventoryTransaction.service.InventoryTransactionService;
import com.huaheng.pc.shipment.shipmentContainerDetail.domain.ShipmentContainerDetail;
import com.huaheng.pc.shipment.shipmentContainerDetail.service.ShipmentContainerDetailService;
import com.huaheng.pc.shipment.shipmentContainerHeader.domain.ShipmentContainerHeader;
import com.huaheng.pc.shipment.shipmentContainerHeader.service.ShipmentContainerHeaderService;
import com.huaheng.pc.shipment.shipmentDetail.domain.ShipmentDetail;
import com.huaheng.pc.shipment.shipmentDetail.service.ShipmentDetailService;
import com.huaheng.pc.shipment.shipmentHeader.domain.ShipmentHeader;
import com.huaheng.pc.shipment.shipmentHeader.service.ShipmentHeaderService;
import com.huaheng.pc.task.taskDetail.domain.TaskDetail;
import com.huaheng.pc.task.taskDetail.service.TaskDetailService;
import com.huaheng.pc.task.taskHeader.domain.ShipmentTaskCreateModel;
import com.huaheng.pc.task.taskHeader.domain.TaskHeader;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * 入库任务创建和完成
 * @author mahua
 * @date 2020/7/14
 */
@Service
public class ShipmentTaskService {

    @Resource
    private ShipmentContainerHeaderService containerHeaderService;
    @Resource
    private ShipmentContainerDetailService shipmentContainerDetailService;
    @Resource
    private LocationService locationService;
    @Resource
    private InventoryDetailService inventoryDetailService;
    @Resource
    private TaskHeaderService taskHeaderService;
    @Resource
    private TaskDetailService taskDetailService;
    @Resource
    private ShipmentDetailService shipmentDetailService;
    @Resource
    private ShipmentHeaderService shipmentHeaderService;
    @Resource
    private InventoryHeaderService inventoryHeaderService;
    @Resource
    private InventoryTransactionService inventoryTransactionService;
    @Resource
    private ContainerService containerService;
    @Resource
    private IMaterialWarningService materialWarningService;
    /**
     * 创建出库任务
     * @param shipmentTaskCreateModel
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult createTaskFromShipmentContainers(ShipmentTaskCreateModel shipmentTaskCreateModel){
        Integer shipmentContainerHeaderId = shipmentTaskCreateModel.getShipmentContainerHeaderIds();
        //获取表头
        ShipmentContainerHeader shipmentContainerHeader = containerHeaderService.getById(shipmentContainerHeaderId);
        if (shipmentContainerHeader == null) {
            return AjaxResult.error("出库货箱" + shipmentContainerHeaderId + "未找到,操作中止");
        }
        if (shipmentContainerHeader.getStatus() >= QuantityConstant.SHIPMENT_CONTAINER_TASK) {
            return AjaxResult.error("出库货箱" + shipmentContainerHeader.getContainerCode() + "已经生成任务,请不要重复生成,操作中止");
        }
        //获取所有子货箱
        List<ShipmentContainerDetail> shipmentContainerDetails = shipmentContainerDetailService.selectByShippingContainerId(shipmentContainerHeader.getId());
        if (shipmentContainerDetails.isEmpty()) {
            return AjaxResult.error("货箱" + shipmentContainerHeader.getContainerCode() + "没有子任务,操作中止");
        }

        //检测库位
        LambdaQueryWrapper<Location> locationLambdaQueryWrapper = Wrappers.lambdaQuery();
        locationLambdaQueryWrapper.eq(Location::getCode, shipmentContainerHeader.getLocationCode())
                .eq(Location::getWarehouseCode, ShiroUtils.getWarehouseCode())
                .eq(Location::getDeleted, false);
        Location location = locationService.getOne(locationLambdaQueryWrapper);
        if (StringUtils.isNull(location)) {
            return AjaxResult.error("库位禁用或不存在!");
        }
        //创建任务头
        TaskHeader task = new TaskHeader();
        task.setTaskType(QuantityConstant.TASK_TYPE_SORTINGSHIPMENT);
        task.setFromLocation(shipmentContainerHeader.getLocationCode());
        task.setToLocation(shipmentContainerHeader.getLocationCode());
        //判断是否整出任务,钱柜和AGV不能整出

        //表示整出优先
        //判断当前子货箱所有数量是否等于该托盘对应的所有库存的数量,
        //这里必须与库存的在库数量对比,后期可能存在一个配盘在执行任务,后一个配盘又在配这个的情况(这个时候不能整出)
        //如果相等,则说明这个货箱包含了所有的数量,则可以整出,否则,创建拣选任务;
        //查询所有库存

        LambdaQueryWrapper<InventoryDetail> inventoryDetailLambdaQueryWrapper = Wrappers.lambdaQuery();
        inventoryDetailLambdaQueryWrapper.eq(InventoryDetail::getLocationCode, shipmentContainerHeader.getLocationCode())
                .eq(InventoryDetail::getWarehouseCode, ShiroUtils.getWarehouseCode());
        List<InventoryDetail> inventories = inventoryDetailService.list(inventoryDetailLambdaQueryWrapper);
        BigDecimal inventoryTotal = new BigDecimal("0");
        for (InventoryDetail item : inventories) {
            inventoryTotal = inventoryTotal.add(item.getQty());
        }
        BigDecimal containerTotal = new BigDecimal("0");
        for (ShipmentContainerDetail item : shipmentContainerDetails) {
            containerTotal = containerTotal.add(item.getQty());
        }
        if (inventoryTotal.compareTo(containerTotal) == 0) {
            //整盘出库
            task.setTaskType(QuantityConstant.TASK_TYPE_WHOLESHIPMENT);
            task.setToLocation("");
        }

        task.setInternalTaskType(QuantityConstant.TASK_INTENERTYPE_PICKING);
        task.setAllocationHeadId(shipmentContainerHeader.getId());
        task.setWarehouseCode(shipmentContainerHeader.getWarehouseCode());
        task.setAssignedUser(ShiroUtils.getLoginName());
        task.setConfirmedBy(ShiroUtils.getLoginName());
        task.setStatus(QuantityConstant.TASK_STATUS_BUILD);
        task.setContainerCode(shipmentContainerHeader.getContainerCode());
        if (!taskHeaderService.save(task)){
            throw new ServiceException("生成任务失败");
        }
        for (ShipmentContainerDetail shipmentContainerDetail : shipmentContainerDetails) {
            TaskDetail taskDetail = new TaskDetail();
            taskDetail.setTaskId(task.getId());
            taskDetail.setInternalTaskType(task.getInternalTaskType());
            taskDetail.setWarehouseCode(task.getWarehouseCode());
            taskDetail.setCompanyCode(task.getCompanyCode());
            taskDetail.setTaskType(task.getTaskType());
            taskDetail.setToInventoryId(shipmentContainerDetail.getInventoryId());
            taskDetail.setAllocationId(shipmentContainerDetail.getId());
            taskDetail.setBillCode(shipmentContainerDetail.getShipmentCode());
            taskDetail.setBillDetailId(shipmentContainerDetail.getShipmentDetailId());
            taskDetail.setMaterialCode(shipmentContainerDetail.getMaterialCode());
            taskDetail.setMaterialName(shipmentContainerDetail.getMaterialName());
            taskDetail.setMaterialSpec(shipmentContainerDetail.getMaterialSpec());
            taskDetail.setMaterialUnit(shipmentContainerDetail.getMaterialUnit());
            taskDetail.setFromInventoryId(shipmentContainerDetail.getInventoryId());
            taskDetail.setQty(shipmentContainerDetail.getQty());
            taskDetail.setContainerCode(task.getContainerCode());
            taskDetail.setFromLocation(task.getFromLocation());
            taskDetail.setToLocation(task.getToLocation());
            taskDetail.setLot(shipmentContainerDetail.getLot());
            taskDetail.setBatch(shipmentContainerDetail.getBatch());
            taskDetail.setProjectNo(shipmentContainerDetail.getProjectNo());
            taskDetail.setStatus(QuantityConstant.TASK_STATUS_BUILD);
            taskDetail.setWaveId(shipmentContainerDetail.getWaveId());
            taskDetail.setInventorySts(shipmentContainerDetail.getInventorySts());
            if (!taskDetailService.save(taskDetail)) {
                throw new ServiceException("新建任务明细失败,sql报错");
            }
            shipmentContainerDetail.setStatus(QuantityConstant.SHIPMENT_CONTAINER_TASK);
            if (!shipmentContainerDetailService.updateById(shipmentContainerDetail)) {
                throw new ServiceException("修改组盘明细状态失败");
            }
        }
        //更新货位状态
        shipmentContainerHeader.setStatus(QuantityConstant.SHIPMENT_CONTAINER_TASK);
        if (!containerHeaderService.updateById(shipmentContainerHeader)) {
            throw new ServiceException("修改组盘头状态失败,sql报错");
        }

        return AjaxResult.success();
    }

    /**
     * 完成出库任务
     * @param task
     */
    @Transactional(rollbackFor = Exception.class)
    public void completeShipmentTask(TaskHeader task) {
        //获取任务明细
        List<TaskDetail> taskDetails = taskDetailService.findByTaskId(task.getId());

        List<Integer> shipmentHeadIds = new ArrayList<>();

        for (TaskDetail taskDetail : taskDetails) {
            if (taskDetail.getStatus() < QuantityConstant.TASK_STATUS_RUNNING) {
                //获取出库子货箱
                ShipmentContainerDetail shipmentContainerDetail = shipmentContainerDetailService.getById(taskDetail.getAllocationId());
                //取出子单据
                ShipmentDetail shipmentDetail = shipmentDetailService.getById(taskDetail.getBillDetailId());
                //暂存id,为更新单据状态准备
                shipmentHeadIds.add(shipmentDetail.getShipmentId());
                //获取对应库存记录
                InventoryDetail inventoryDetail = inventoryDetailService.getById(taskDetail.getToInventoryId());
                if (inventoryDetail == null) {
                    throw new ServiceException("任务明细对应的库存ID【" + taskDetail.getToInventoryId().toString() + "】不存在!");
                }
                //减扣库存单
                InventoryHeader inventoryHeader = inventoryHeaderService.getById(inventoryDetail.getInventoryHeaderId());

                //扣减库存明细
                inventoryDetail.setTaskQty(inventoryDetail.getTaskQty().subtract(taskDetail.getQty()));
                inventoryDetail.setQty(inventoryDetail.getQty().subtract(taskDetail.getQty()));

                if (inventoryDetail.getQty().signum() == -1) {
                    throw new ServiceException("扣减库存大于wms库存");
                }
                if (inventoryDetail.getQty().signum() == 0
                    && inventoryDetail.getTaskQty().signum() == 0) {
                    //如果库存没有了,就删除这个库存
                    inventoryDetailService.removeById(inventoryDetail.getId());
                    inventoryHeader.setTotalQty(inventoryHeader.getTotalQty().subtract(taskDetail.getQty()));
                    inventoryHeader.setTotalLines(inventoryHeader.getTotalLines() - 1);
                    if (inventoryHeader.getTotalQty().signum() == 0){
                        inventoryHeaderService.removeById(inventoryHeader.getId());
                    } else {
                        inventoryHeaderService.updateById(inventoryHeader);
                    }
                } else {
                    //否则更新这个库存
                    inventoryDetailService.updateById(inventoryDetail);
                    inventoryHeader.setTotalQty(inventoryHeader.getTotalQty().subtract(taskDetail.getQty()));
                    inventoryHeaderService.updateById(inventoryHeader);
                    inventoryHeaderService.updateById(inventoryHeader);
                }
                //设置子任务状态为已执行
                taskDetail.setStatus(QuantityConstant.TASK_STATUS_COMPLETED);
                taskDetailService.updateById(taskDetail);
                //修改出库组盘明细状态
                shipmentContainerDetail.setStatus(QuantityConstant.SHIPMENT_CONTAINER_FINISHED);
                shipmentContainerDetailService.updateById(shipmentContainerDetail);
                //记录库存交易记录
                InventoryTransaction inventoryTransaction = new InventoryTransaction();
                inventoryTransaction.setWarehouseCode(task.getWarehouseCode());
                inventoryTransaction.setCompanyCode(shipmentDetail.getCompanyCode());
                inventoryTransaction.setLocationCode(inventoryDetail.getLocationCode());
                inventoryTransaction.setContainerCode(inventoryDetail.getContainerCode());
                inventoryTransaction.setTransactionType(QuantityConstant.INVENTORY_TRANSACTION_SHIPMENT);
                inventoryTransaction.setMaterialCode(shipmentDetail.getMaterialCode());
                inventoryTransaction.setMaterialName(shipmentDetail.getMaterialName());
                inventoryTransaction.setMaterialSpec(shipmentDetail.getMaterialSpec());
                inventoryTransaction.setMaterialUnit(shipmentDetail.getMaterialUnit());
                inventoryTransaction.setBillCode(taskDetail.getBillCode());
                inventoryTransaction.setBillDetailId(shipmentDetail.getId());
                inventoryTransaction.setBatch(shipmentDetail.getBatch());
                inventoryTransaction.setLot(shipmentDetail.getLot());
                inventoryTransaction.setProjectNo(shipmentDetail.getProjectNo());
                inventoryTransaction.setQcCheck(inventoryDetail.getQcCheck());
                inventoryTransaction.setSupplierCode(inventoryDetail.getSupplierCode());
                inventoryTransaction.setManufactureDate(shipmentDetail.getManufactureDate());
                inventoryTransaction.setExpirationDate(shipmentDetail.getExpirationDate());
                inventoryTransaction.setInventorySts(inventoryDetail.getInventorySts());
                //这里取反,更符合出库的语义,同时方便对记录进行统计
                inventoryTransaction.setTaskQty(taskDetail.getQty());
                inventoryTransactionService.save(inventoryTransaction);
                materialWarningService.materialWarning(taskDetail.getMaterialCode(), taskDetail.getCompanyCode());
            }
        }
        //设置主任务为已执行
        task.setStatus(QuantityConstant.TASK_STATUS_COMPLETED);
        taskHeaderService.updateById(task);
        /* 更新库位和容器*/
        updateLocationContainer(task.getFromLocation(), task.getToLocation(), task.getContainerCode(), task.getTaskType());

        //设置出库货箱表头状态为拣货任务完成
        LambdaUpdateWrapper<ShipmentContainerHeader> shipmentContainerHeaderLambdaUpdateWrapper = Wrappers.lambdaUpdate();
        shipmentContainerHeaderLambdaUpdateWrapper.eq(ShipmentContainerHeader::getId, task.getAllocationHeadId())
            .set(ShipmentContainerHeader::getStatus, QuantityConstant.SHIPMENT_CONTAINER_REVIEWSUCCESS);
        if (!containerHeaderService.update(shipmentContainerHeaderLambdaUpdateWrapper)) {
            throw new ServiceException("更新组盘头状态失败");
        }

        //修改出库单状态
        List<TaskDetail> taskDetailList = taskDetailService.findByTaskId(task.getId());
        HashSet<Integer> ids = new HashSet<>();
        for (TaskDetail taskDetail : taskDetailList) {
            ShipmentDetail shipmentDetail = shipmentDetailService.getById(taskDetail.getBillDetailId());
            if (StringUtils.isNull(shipmentDetail)) {
                throw new ServiceException("查找出库单明细失败");
            }
            if (shipmentDetail.getShipQty().compareTo(shipmentDetail.getRequestQty()) == 0) {
                shipmentDetail.setStatus(QuantityConstant.SHIPMENT_HEADER_COMPLETED);
                shipmentDetailService.updateById(shipmentDetail);
            }
            ids.add(shipmentDetail.getShipmentId());
        }

        /*更新出库单状态*/
        for (Integer id : ids) {
            ShipmentHeader shipmentHeader = shipmentHeaderService.getById(id);
            if (shipmentHeader != null) {
                Map<String, Integer> status = shipmentDetailService.selectStatus(shipmentHeader.getId());
                Integer maxStatus = status.get("maxStatus");
                Integer minStatus = status.get("minStatus");
                if (maxStatus.equals(QuantityConstant.SHIPMENT_HEADER_COMPLETED)) {
                    shipmentHeader.setFirstStatus(QuantityConstant.SHIPMENT_HEADER_COMPLETED);
                }
                if (minStatus.equals(QuantityConstant.SHIPMENT_HEADER_COMPLETED)) {
                    shipmentHeader.setLastStatus(QuantityConstant.SHIPMENT_HEADER_COMPLETED);
                }
                shipmentHeader.setLastUpdatedBy(ShiroUtils.getLoginName());
                shipmentHeader.setLastUpdated(new Date());
                shipmentHeaderService.updateById(shipmentHeader);
            }
        }
    }

    /**
     * 出库任务完成时更新库位和容器状态
     * @param fromLocation 源库位
     * @param toLocation 目标库位
     * @param containerCode 容器编码
     * @param taskType 任务类型
     */
    public void updateLocationContainer(String fromLocation, String toLocation, String containerCode, Integer taskType){
        //将库位状态改为空闲,如果是整出的对应的容器也清空
        Location fromLocationRecord = locationService.findLocationByCode(fromLocation);
        if (StringUtils.isNull(fromLocationRecord)) {
            throw new ServiceException("系统没有" + fromLocation + "库位");
        }
        /* 如果目标库位与源库位不一样时,需要更新两个库位*/
        if (StringUtils.isNotEmpty(toLocation)
                && !fromLocation.equals(toLocation)) {
            Location toLocationRecord = locationService.findLocationByCode(toLocation);
            if (StringUtils.isNull(fromLocationRecord)) {
                throw new ServiceException("系统没有" + toLocation + "库位");
            }
            toLocationRecord.setStatus("empty");
            if (taskType.equals(QuantityConstant.TASK_TYPE_WHOLESHIPMENT)) {
                toLocationRecord.setContainerCode("");
            }
            locationService.updateById(toLocationRecord);
            fromLocationRecord.setContainerCode("");
        }
        fromLocationRecord.setStatus("empty");
        if (taskType.equals(QuantityConstant.TASK_TYPE_WHOLESHIPMENT)) {
            fromLocationRecord.setContainerCode("");
        }
        locationService.updateById(fromLocationRecord);

        Container container = containerService.findAllByCode(containerCode);
        if (StringUtils.isEmpty(containerCode)) {
            throw new ServiceException("系统无"+container+"容器");
        }

        if (taskType.equals(QuantityConstant.TASK_TYPE_WHOLESHIPMENT)) {
            if ("LS".equals(container.getContainerType())) {
                if (!containerService.removeById(container.getId())) {
                    throw new ServiceException("删除临时容器失败");
                }
            } else {
                containerService.updateLocationCodeAndStatus(containerCode, "", "empty");
            }
        } else {
            //查询是否存在关联的库存,入如果没有就修改容器状态为empty
            LambdaQueryWrapper<InventoryDetail> inventoryDetaillambdaQueryWrapper = Wrappers.lambdaQuery();
            inventoryDetaillambdaQueryWrapper.eq(InventoryDetail::getContainerCode, containerCode);
            List<InventoryDetail> detailList = inventoryDetailService.list();
            //库存查询不到该容器就把容器状态改为可用
            if (detailList.isEmpty()) {
                containerService.updateLocationCodeAndStatus(containerCode, "", "empty");
            }
        }
    }
}