WarehouseManagerImpl.java

package com.mycim.server.asm.manager.impl;

import com.fa.sesa.exception.Assert;
import com.fa.sesa.exception.Errors;
import com.fa.sesa.threadlocal.LocalContext;
import com.mycim.framework.jdbc.Page;
import com.mycim.framework.utils.lang.BooleanUtils;
import com.mycim.framework.utils.lang.StringUtils;
import com.mycim.framework.utils.lang.collections.CollectionUtils;
import com.mycim.framework.utils.lang.collections.MapUtils;
import com.mycim.framework.utils.lang.math.NumberUtils;
import com.mycim.server.asm.dao.WarehouseDAO;
import com.mycim.server.asm.manager.LotInventoryManager;
import com.mycim.server.asm.manager.MaterialManager;
import com.mycim.server.asm.manager.WarehouseManager;
import com.mycim.server.base.manager.NamedObjectManager;
import com.mycim.server.base.manager.TransactionLogManager;
import com.mycim.server.ems.manager.EquipmentBomManager;
import com.mycim.server.prp.manager.OperationManager;
import com.mycim.server.rcp.manager.RecipeManager;
import com.mycim.server.wip.manager.DiffBatchQueryManager;
import com.mycim.server.wip.manager.JobQueryManager;
import com.mycim.server.wip.manager.LotBondingManager;
import com.mycim.valueobject.MessageIdList;
import com.mycim.valueobject.ObjectList;
import com.mycim.valueobject.bas.EquipmentBomInfo;
import com.mycim.valueobject.bas.TransactionLog;
import com.mycim.valueobject.consts.BOMLossTypeConst;
import com.mycim.valueobject.consts.TransactionNames;
import com.mycim.valueobject.inv.*;
import com.mycim.valueobject.inv.value.WarehouseNames;
import com.mycim.valueobject.prp.Item;
import com.mycim.valueobject.prp.Operation;
import com.mycim.valueobject.prp.Recipe;
import com.mycim.valueobject.wip.Job;
import com.mycim.valueobject.wip.LotConsumesMaterialHistory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.util.*;

/**
 * @author shijie.deng
 * @date 2019/8/27
 **/
@Service
@Transactional
public class WarehouseManagerImpl implements WarehouseManager {

    @Autowired
    private WarehouseDAO warehouseDAO;

    @Autowired
    private MaterialManager materialManager;

    @Autowired
    private TransactionLogManager transactionLogManager;

    @Autowired
    private LotInventoryManager lotInventoryManager;

    @Autowired
    private OperationManager operationManager;

    @Autowired
    private JobQueryManager jobQueryManager;

    @Autowired
    private NamedObjectManager namedObjectManager;

    @Autowired
    private EquipmentBomManager equipmentBomManager;

    @Autowired
    private LotBondingManager lotBondingManager;

    @Autowired
    private DiffBatchQueryManager diffBatchQueryManager;

    @Autowired
    private RecipeManager recipeManager;

    private static final String BOM_BANK = "BOM_BANK";

    private static final String MEASURABLE_TYPE = "MeasurableType";

    private static final String COUNTING_TYPE = "CountingType";

    private static final String BY_WAFER = "By Wafer";

    private static final String BY_LOT = "By Lot";

    private static final String BY_BATCH = "By Batch";

    private static final String ON = "ON";

    private static final String OFF = "OFF";

    @Override
    public long consumeItemQty(List<Map<String, Object>> consumedItems, String userId, long facilityRrn,
                               Long checklistJobRrn) {
        TransactionLog transactionLog = transactionLogManager.startTransactionLog("CONSUME", userId);

        for (Map<String, Object> consumedItem : consumedItems) {
            Long itemRrn = MapUtils.getLong(consumedItem, "itemRrn");
            Double consumedQty = MapUtils.getDouble(consumedItem, "consumedQty");
            Item item = warehouseDAO.getItem(itemRrn);
            Long warehouseRrn = item.getDefaultWarehouseRrn();
            String lotNumber = MapUtils.getStringCheckNull(consumedItem, "lotNumber");
            String orderNumber = MapUtils.getStringCheckNull(consumedItem, "orderNumber");
            String ticketNumber = MapUtils.getStringCheckNull(consumedItem, "ticketNumber");
            Integer sequenceNumber = MapUtils.getInteger(consumedItem, "sequenceNumber");
            Long lotRrn = MapUtils.getLong(consumedItem, "lotRrn");
            Long stepSequence = MapUtils.getLong(consumedItem, "stepSequence");
            String comments = MapUtils.getStringCheckNull(consumedItem, "comments");

            warehouseDAO.increaseItemQty((double) 0, consumedQty, (double) 0, itemRrn);

            if (sequenceNumber == null) {
                sequenceNumber = 0;
            }
            warehouseDAO
                    .increaseWareHouseInventory(itemRrn, warehouseRrn, null, null, (double) 0, consumedQty, (double) 0);
            warehouseDAO
                    .createInventoryTransactionHistory(transactionLog.getTransRrn(), sequenceNumber, itemRrn, lotNumber,
                                                       facilityRrn, transactionLog.getTransId(), consumedQty,
                                                       transactionLog.getTransStartTimestamp(), warehouseRrn, "", null,
                                                       "", null, "", null, "", "", ticketNumber, checklistJobRrn,
                                                       lotRrn, stepSequence, comments);

        }

        transactionLogManager.markTransactionLog(transactionLog);
        return transactionLog.getTransRrn();
    }

    @Override
    public List<MaterialDO> getWarehouseInventoryList(Long warehouseRrn, Map<String, String> condition) {
        List<WarehouseInventoryDO> warehouseInventoryList = warehouseDAO
                .getWarehouseInventoryListForMaterial(warehouseRrn, condition);
        List<MaterialDO> results = new ArrayList<>();
        for (WarehouseInventoryDO warehouseInventoryDO : warehouseInventoryList) {
            MaterialDO materialDO = new MaterialDO();
            materialDO.setInstanceRrn(warehouseInventoryDO.getItemRrn());
            materialDO = materialManager.getMaterial(materialDO);
            if (materialDO != null) {
                materialDO.setReceiptQty(warehouseInventoryDO.getReceiptQty());
                materialDO.setIssueQty(warehouseInventoryDO.getIssueQty());
                materialDO.setAdjustQty(warehouseInventoryDO.getAdjustQty());

                results.add(materialDO);
            }
        }
        return results;
    }

    @Override
    public List<MaterialDO> getWarehouseInventoryListForMaterialWithExt(Long warehouseRrn,
                                                                        Map<String, String> condition) {
        List<WarehouseInventoryDO> warehouseInventoryList = warehouseDAO
                .getWarehouseInventoryListForMaterialWithExt(warehouseRrn, condition);
        List<MaterialDO> results = new ArrayList<>();
        for (WarehouseInventoryDO warehouseInventoryDO : warehouseInventoryList) {
            MaterialDO materialDO = new MaterialDO();
            materialDO.setInstanceRrn(warehouseInventoryDO.getItemRrn());
            materialDO = materialManager.getMaterial(materialDO);
            if (materialDO != null) {
                materialDO.setReceiptQty(warehouseInventoryDO.getReceiptQty());
                materialDO.setIssueQty(warehouseInventoryDO.getIssueQty());
                materialDO.setAdjustQty(warehouseInventoryDO.getAdjustQty());
                results.add(materialDO);
            }
        }
        return results;
    }

    @Override
    public void setExpirationDateForReceive(Integer expirationLength, LotInventoryDO lotInventory) {
        if (lotInventory.getExpirationDate() == null) {
            int expirationLengthTemp = expirationLength == null ? 0 : expirationLength;
            Calendar c = Calendar.getInstance();
            c.setTime(lotInventory.getReceiptDate());
            c.add(Calendar.DAY_OF_MONTH, expirationLengthTemp);
            lotInventory.setExpirationDate(new Timestamp(c.getTime().getTime()));
            lotInventory.setAvailabilityDays(NumberUtils.toDouble(Integer.toString(expirationLengthTemp)));
        } else {
            long availabilityDays =
                    (lotInventory.getExpirationDate().getTime() - lotInventory.getReceiptDate().getTime()) / 1000;
            if (availabilityDays > 0) {
                availabilityDays = availabilityDays / 3600 / 24;
            }
            lotInventory.setAvailabilityDays(NumberUtils.toDouble(Long.toString(availabilityDays)));
        }
    }

    @Override
    public void saveReceivedMaterialToWarehouse(Long facilityRrn, String userId, List<WarehouseTransBO> receiveTrans) {
        TransactionLog transactionLog = transactionLogManager.startTransactionLog(userId, TransactionNames.RECEIVE_KEY);
        transactionLog.setComments("库房接收");

        long transSequence = 1;
        for (WarehouseTransBO warehouseTrans : receiveTrans) {

            setLotInventoryQty(transactionLog.getTransId(), warehouseTrans);

            InventoryTransHistoryDO inventoryTransHistory = buildInventoryTransHistory(facilityRrn, warehouseTrans,
                                                                                       transactionLog, transSequence++);

            saveReceivedMaterialToWarehouse(warehouseTrans.getLotInventoryDO(), inventoryTransHistory);
        }
        transactionLogManager.markTransactionLog(transactionLog);
    }

    @Override
    public void saveConsumeMaterialFromWarehouse(Long facilityRrn, String userId,
                                                 List<WarehouseTransBO> consumptionTrans) {
        TransactionLog transactionLog = transactionLogManager
                .startTransactionLog(userId, TransactionNames.MANUAL_CONSUME_KEY);
        transactionLog.setComments("库房手动消耗");

        long transSequence = 1;
        for (WarehouseTransBO warehouseTrans : consumptionTrans) {
            setLotInventoryQty(TransactionNames.MANUAL_CONSUME_KEY, warehouseTrans);
            InventoryTransHistoryDO inventoryTransHistory = buildInventoryTransHistory(facilityRrn, warehouseTrans,
                                                                                       transactionLog, transSequence++);

            saveConsumeMaterialFromWarehouse(warehouseTrans.getLotInventoryDO(), inventoryTransHistory);
        }

        transactionLogManager.markTransactionLog(transactionLog);

    }

    @Override
    public WarehouseInventoryDO getWarehouseInventory(Long warehouseRrn, Long materialRrn) {
        return warehouseDAO.getWarehouseInventory(warehouseRrn, materialRrn);
    }

    @Override
    public void saveConvertMaterialFromWarehouse(Long facilityRrn, String userId, List<WarehouseTransBO> convertTrans) {
        for (WarehouseTransBO warehouseTrans : convertTrans) {
            TransactionLog transactionLog = transactionLogManager
                    .startTransactionLog(userId, warehouseTrans.getTransType());
            transactionLog.setComments("物料类型转换");
            long transSequence = 1;

            // 消耗源物料
            setLotInventoryQty(TransactionNames.CONSUME_KEY, warehouseTrans);
            InventoryTransHistoryDO inventoryTransHistory = buildInventoryTransHistory(facilityRrn, warehouseTrans,
                                                                                       transactionLog, transSequence);

            LotInventoryDO lotInventory = warehouseTrans.getLotInventoryDO();
            saveConsumeMaterialFromWarehouse(lotInventory, inventoryTransHistory);

            // 接收新物料
            lotInventory.setLotNumber(warehouseTrans.getTargetLotNumber());
            lotInventory.setReceiptQty(warehouseTrans.getTransQty());
            lotInventory.setIssueQty(0D);
            lotInventory.setAdjustQty(0D);
            lotInventory.setIssuePriority(null);
            lotInventory.setStatus(WarehouseNames.ACTIVE_STATUS);
            lotInventory.setReceiptDate(new Timestamp(System.currentTimeMillis()));
            setExpirationDateForReceive(NumberUtils.toInt(Double.toString(lotInventory.getAvailabilityDays())),
                                        lotInventory);

            inventoryTransHistory.setMaterialLotNumber(lotInventory.getLotNumber());
            inventoryTransHistory.setTransSequence(++transSequence);

            saveReceivedMaterialToWarehouse(lotInventory, inventoryTransHistory);

            transactionLogManager.markTransactionLog(transactionLog);
        }
    }

    @Override
    public void saveStocktakeMaterialFromWarehouse(Long facilityRrn, String userId,
                                                   List<WarehouseTransBO> stocktakeTrans) {
        TransactionLog transactionLog = transactionLogManager.startTransactionLog(userId, TransactionNames.ADJUST_KEY);
        transactionLog.setComments("库房盘点");
        long transSequence = 1;
        for (WarehouseTransBO warehouseTrans : stocktakeTrans) {

            setLotInventoryQty(TransactionNames.ADJUST_KEY, warehouseTrans);
            InventoryTransHistoryDO inventoryTransHistory = buildInventoryTransHistory(facilityRrn, warehouseTrans,
                                                                                       transactionLog, transSequence++);

            //当前逻辑:ITEM表字段ISSUE_QTY=IssueQty+|TransQty|,需卡控不能超过字段ISSUE_QTY的最大精度
            Item item = warehouseDAO.getItem(warehouseTrans.getLotInventoryDO().getItemRrn());
            Assert.state(((Math.abs(warehouseTrans.getTransQty()) + item.getIssueQty()) <= 9999999999L),
                         Errors.create().key(MessageIdList.MATERIAL_ISSUEQTY_EXCEEDED)
                               .content("Consumed quantity cannot exceed the maximum value:9999999999!").build());
            saveConsumeMaterialFromWarehouse(warehouseTrans.getLotInventoryDO(), inventoryTransHistory);
        }
        transactionLogManager.markTransactionLog(transactionLog);
    }

    @Override
    public void saveTransferMaterialFromWarehouse(Long facilityRrn, String userId,
                                                  List<WarehouseTransBO> transferTrans) {
        for (WarehouseTransBO warehouseTrans : transferTrans) {

            TransactionLog transactionLog = transactionLogManager
                    .startTransactionLog(userId, TransactionNames.TRANSFER_KEY);
            transactionLog.setComments("库存转移");
            long transSequence = 1;

            setLotInventoryQty(TransactionNames.ADJUST_KEY, warehouseTrans);
            InventoryTransHistoryDO inventoryTransHistory = buildInventoryTransHistory(facilityRrn, warehouseTrans,
                                                                                       transactionLog, transSequence);
            inventoryTransHistory.setTransId(TransactionNames.TRANSFEROUT_KEY);
            inventoryTransHistory.setComments(warehouseTrans.getFromComments());

            LotInventoryDO lotInventory = warehouseTrans.getLotInventoryDO();

            saveStocktakeMaterialFromWarehouse(lotInventory, inventoryTransHistory);

            lotInventory.setWarehouseRrn(warehouseTrans.getToWarehouseRrn());
            lotInventory.setWarehouseId(warehouseTrans.getToWarehouseId());
            lotInventory.setReceiptQty(inventoryTransHistory.getTransQty());
            lotInventory.setIssueQty(0D);
            lotInventory.setAdjustQty(0D);
            lotInventory.setIssuePriority(null);
            lotInventory.setStatus(WarehouseNames.ACTIVE_STATUS);
            lotInventory.setReceiptDate(new Timestamp(System.currentTimeMillis()));

            setExpirationDateForReceive(NumberUtils.toInt(Double.toString(lotInventory.getAvailabilityDays())),
                                        lotInventory);

            inventoryTransHistory.setTransId(TransactionNames.TRANSFERIN_KEY);
            inventoryTransHistory.setTransSequence(++transSequence);
            inventoryTransHistory.setComments(warehouseTrans.getToComments());

            saveReceivedMaterialToWarehouse(lotInventory, inventoryTransHistory);

            transactionLogManager.markTransactionLog(transactionLog);
        }
    }

    @Override
    public Page getInventoryTransHistoryForPage(Page page, Long warehouseRrn, Long materialRrn, String lotNumber,
                                                String transId, Timestamp startDateTime, Timestamp endDateTime) {
        return warehouseDAO
                .getInventoryTransHistoryForPage(page, warehouseRrn, materialRrn, lotNumber, transId, startDateTime,
                                                 endDateTime);
    }

    @Override
    public void consumeMaterialFromWarehouseForBOM(long facilityRrn, String userId, Long runRrn,
                                                   List<WarehouseTransBO> consumptionTrans) {

        TransactionLog transactionLog = transactionLogManager
                .startTransactionLog(userId, TransactionNames.BOR_CONSUME_KEY);

        long transSequence = 1;
        for (WarehouseTransBO warehouseTrans : consumptionTrans) {
            LotInventoryDO lotInventory = warehouseTrans.getLotInventoryDO();

            if (BOMLossTypeConst.QUANTITY.equals(warehouseTrans.getBorLossType())) {
                InventoryTransHistoryDO inventoryTransHistory = buildInventoryTransHistory(facilityRrn, warehouseTrans,
                                                                                           transactionLog,
                                                                                           transSequence);
                inventoryTransHistory.setBorRrn(warehouseTrans.getBorRrn());
                inventoryTransHistory.setBorVersion(warehouseTrans.getBorVersion());
                inventoryTransHistory.setRunRrn(runRrn);

                // 库房消耗
                this.saveConsumeMaterialFromWarehouse(lotInventory, inventoryTransHistory);
            }

            // BOM消耗记录
            LotConsumesMaterialHistory lotConsumesMaterialHistory = new LotConsumesMaterialHistory();

            lotConsumesMaterialHistory.setTransRrn(transactionLog.getTransRrn());
            lotConsumesMaterialHistory.setTransSequence(transSequence);

            lotConsumesMaterialHistory.setBorRrn(warehouseTrans.getBorRrn());
            lotConsumesMaterialHistory.setBorVersion(warehouseTrans.getBorVersion());
            lotConsumesMaterialHistory.setBorResourceSeq(warehouseTrans.getBorResourceSeq());
            lotConsumesMaterialHistory.setBorLossType(warehouseTrans.getBorLossType());
            lotConsumesMaterialHistory.setBorBasisCode(warehouseTrans.getBorBasisCode());

            lotConsumesMaterialHistory.setLotNumber(lotInventory.getLotNumber());
            lotConsumesMaterialHistory.setItemRrn(lotInventory.getItemRrn());
            lotConsumesMaterialHistory.setWarehouseRrn(lotInventory.getWarehouseRrn());
            lotConsumesMaterialHistory.setMaterialType(lotInventory.getMaterialType());

            lotConsumesMaterialHistory.setRunRrn(runRrn);
            lotConsumesMaterialHistory.setLotRrns(warehouseTrans.getLotRrnsInfo());
            lotConsumesMaterialHistory.setLotIds(warehouseTrans.getLotIdsInfo());

            lotConsumesMaterialHistory.setConsumptionQty(lotInventory.getIssueQty());
            lotConsumesMaterialHistory.setConsumptionUserId(userId);

            this.insertLotConsumesMaterialHistory(lotConsumesMaterialHistory);

            transSequence++;
        }

        transactionLogManager.markTransactionLog(transactionLog);
    }

    @Override
    public Page getLotConsumesMaterialHistoryForPage(Page page, Map<String, Object> conditions) {
        return warehouseDAO.getLotConsumesMaterialHistoryForPage(page, conditions);
    }

    @Override
    public Page getReceiveHistoryForPage(Page page, Long warehouseRrn, Long materialRrn, String lotNumber,
                                         Timestamp startDateTime, Timestamp endDateTime) {
        return warehouseDAO
                .getReceiveHistoryForPage(page, warehouseRrn, materialRrn, lotNumber, startDateTime, endDateTime);
    }

    @Override
    public void consumeMaterialFromWarehouse4Pms(long facilityRrn, String userId,
                                                 List<WarehouseTransBO> consumptionTrans) {
        TransactionLog transactionLog = transactionLogManager
                .startTransactionLog(userId, TransactionNames.PMS_CONSUME_KEY);

        long transSequence = 1;
        for (WarehouseTransBO warehouseTrans : consumptionTrans) {
            LotInventoryDO lotInventory = warehouseTrans.getLotInventoryDO();
            InventoryTransHistoryDO inventoryTransHistory = buildInventoryTransHistory(facilityRrn, warehouseTrans,
                                                                                       transactionLog, transSequence);

            // 库房消耗
            this.saveConsumeMaterialFromWarehouse(lotInventory, inventoryTransHistory);

            transSequence++;
        }

        transactionLogManager.markTransactionLog(transactionLog);
    }

    /**
     * bom 消耗记录insert
     *
     * @param consumptionTrans
     * @param map
     */
    private void consumeMaterialFromWarehouse4Bom(List<WarehouseTransBO> consumptionTrans, Map map) {

        TransactionLog transactionLog = transactionLogManager
                .startTransactionLog(LocalContext.getUserId(), TransactionNames.BOM_CONSUME);

        long transSequence = 1;
        String consumeMode = MapUtils.getString(map, "consumeMode");

        for (WarehouseTransBO warehouseTrans : consumptionTrans) {
            LotInventoryDO lotInventory = warehouseTrans.getLotInventoryDO();
            InventoryTransHistoryDO inventoryTransHistory = buildInventoryTransHistory(LocalContext.getFacilityRrn(),
                                                                                       warehouseTrans, transactionLog,
                                                                                       transSequence);
            if (BY_BATCH.equals(consumeMode)) {
                inventoryTransHistory.setBatchId(MapUtils.getString(map, "batchId"));
            } else {
                inventoryTransHistory.setLotRrn(MapUtils.getLong(map, "lotRrn"));
            }
            inventoryTransHistory.setStepSequence(MapUtils.getLong(map, "flowSeq"));
            //bom消耗记录
            LotStepBomHistoryDO lotStepBomHistoryDO = buildLotStepBom(inventoryTransHistory, map);
            materialManager.insertLotStepBomDao(lotStepBomHistoryDO);
            // 库房消耗
            this.saveConsumeMaterialFromWarehouse(lotInventory, inventoryTransHistory);

            transSequence++;
        }

        transactionLogManager.markTransactionLog(transactionLog);
    }

    /**
     * BOM 消耗
     *
     * @param material
     * @param consumeQty
     * @param map
     */
    @Override
    public void consumeMaterialFromWarehouseForBom(MaterialDO material, Integer consumeQty, Map map) {
        long facilityRrn = LocalContext.getFacilityRrn();
        WarehouseTransBO warehouseTrans;
        LotInventoryDO lotInventory;
        Operation warehouse = operationManager.getOperation(BOM_BANK, facilityRrn);
        List<WarehouseTransBO> convertTrans = new ArrayList<>();
        //找到需要消耗的物料的批次
        List<LotInventoryDO> lids = lotInventoryManager
                .getAvailableLotInventory(material.getInstanceRrn(), warehouse.getInstanceRrn(), null);
        Assert.isFalse(lids == null || lids.isEmpty(),
                       Errors.create().key(MessageIdList.NO_HAVE_BOM_LOT).content("{} has no available material lot!")
                             .args(material.getInstanceId()).build());
        String consumeMode = MapUtils.getString(map, "consumeMode");

        String lotNumber = "";
        int remainQty = consumeQty;
        int consume;

        //先消耗主料,集合按照主辅料进行排序
        Collections.sort(lids, new Comparator<LotInventoryDO>() {
            @Override
            public int compare(LotInventoryDO o1, LotInventoryDO o2) {
                Integer o1MaterType = Integer
                        .parseInt(StringUtils.isNotBlank(o1.getAttributeData4()) ? o1.getAttributeData4() : "0");
                Integer o2MaterType = Integer
                        .parseInt(StringUtils.isNotBlank(o2.getAttributeData4()) ? o2.getAttributeData4() : "0");
                return o2MaterType.compareTo(o1MaterType);

            }
        });

        for (LotInventoryDO lid : lids) {
            //多个LotNumber消耗
            if (lid.getTotalQuantity() <= 0) {
                continue;
            }
            if (remainQty <= 0) {
                break;
            }
            if (lid.getTotalQuantity() > remainQty) {
                consume = remainQty;
                remainQty = remainQty - consumeQty;
            } else {
                consume = lid.getTotalQuantity().intValue();
                remainQty = remainQty - consume;
            }
            lotNumber = lid.getLotNumber();
            Double qty = NumberUtils.toDouble(Integer.toString(consume));
            lotInventory = lotInventoryManager
                    .getLotInventory(lotNumber, material.getInstanceRrn(), warehouse.getInstanceRrn());
            lotInventory.setReceiptQty(0D);
            lotInventory.setAdjustQty(0D);
            lotInventory.setIssueQty(qty);

            warehouseTrans = new WarehouseTransBO(lotInventory);
            warehouseTrans.setTransComments(consumeMode);
            warehouseTrans.setTransQty(qty);
            convertTrans.add(warehouseTrans);
        }
        consumeMaterialFromWarehouse4Bom(convertTrans, map);
    }

    /**
     * BOM 消耗计算
     *
     * @param job
     */
    @Override
    public void calculateConsumeQtyForBom(Job job) {
        List<Map> lotList = jobQueryManager.getJobList(job.getJobRrn(), ObjectList.JOB_KEY);
        Long eqptRrn = job.getEqptRrn();
        //获取设备上绑定的所有BOM
        List<EquipmentBomInfo> equipmentBomList = equipmentBomManager.getEquipmentBomList(eqptRrn, 0);
        if (CollectionUtils.isEmpty(equipmentBomList)) {
            return;
        }
        for (Map map : lotList) {
            Long lotRrn = MapUtils.getLong(map, "lotRrn");
            if (lotBondingManager.checkBondLotConsume(lotRrn)) {
                continue;
            }
            String batchId = diffBatchQueryManager.getLotBatchId(lotRrn);
            String lotType = MapUtils.getString(map, "lotType");
            String recipeId = MapUtils.getString(map, "recipeId");
            Recipe recipe = recipeManager.getRecipe(recipeId, LocalContext.getFacilityRrn());
            long mainRecipeRrn = recipeManager.isMainRecipe(recipe.getInstanceRrn());
            Recipe mainRecipe = recipeManager.getRecipe(mainRecipeRrn);
            for (EquipmentBomInfo equipmentBom : equipmentBomList) {
                Integer consumeQty = 0;
                String consumeType = equipmentBom.getConsumeType();
                String consumeMode = equipmentBom.getConsumeMode();
                MaterialDO material = new MaterialDO();
                material.setInstanceRrn(equipmentBom.getMaterialRrn());
                material = new MaterialDO(equipmentBom.getMaterialId(), namedObjectManager
                        .getNamedSpace(LocalContext.getFacilityRrn(), ObjectList.ITEM_KEY), ObjectList.ITEM_KEY);
                material = materialManager.getMaterial(material);
                Assert.isFalse(material == null || material.getInstanceRrn() <= 0,
                               Errors.create().key(MessageIdList.BOM_ID_NOT_EXIST).content("BOM ID not exist!")
                                     .args(equipmentBom.getMaterialId()).build());
                int totalQuantity = materialManager.getMaterialTotalQuantity(material.getInstanceRrn());
                String lotTypes = material.getAttribute3();
                Boolean consumeFlag = Boolean.FALSE;
                if (COUNTING_TYPE.equals(consumeType)) {
                    //check lotType
                    if (!StringUtils.isNotEmptyTrim(lotTypes)) {
                        continue;
                    }
                    consumeFlag = StringUtils.contains(lotTypes, lotType);
                    //check  consumeMode
                    if (consumeFlag) {
                        if (BY_WAFER.equals(consumeMode)) {
                            consumeQty += MapUtils.getInteger(map, "qty1");
                        } else if (BY_LOT.equals(consumeMode)) {
                            consumeQty += 1;
                        } else if ((BY_BATCH.equals(consumeMode)) && StringUtils.isNotBlank(batchId) &&
                                BooleanUtils.isFalse(equipmentBom.getBatchFlag())) {
                            // 当选择by batch 方式消耗并且lot 在 batch 出站时进行消耗计算,通过batchFlag标记已经消耗过了
                            equipmentBom.setBatchFlag(true);
                            consumeQty += 1;
                        }
                    }
                } else if (MEASURABLE_TYPE.equals(consumeType)) {
                    if (!equipmentBom.getRecipeId().equals(mainRecipe.getInstanceId())) {
                        continue;
                    }
                    //check lot type
                    if (ON.equals(equipmentBom.getLotTypeFlag())) {
                        consumeFlag = StringUtils.contains(lotTypes, lotType);
                    } else if (OFF.equals(equipmentBom.getLotTypeFlag())) {
                        consumeFlag = true;
                    }
                    //check  consumeMode
                    if (consumeFlag) {
                        if (BY_WAFER.equals(consumeMode)) {
                            consumeQty += MapUtils.getInteger(map, "qty1");
                        } else if (BY_LOT.equals(consumeMode)) {
                            consumeQty += 1;
                        } else if ((BY_BATCH.equals(consumeMode)) && StringUtils.isNotBlank(batchId) &&
                                BooleanUtils.isFalse(equipmentBom.getBatchFlag())) {
                            // 当选择by batch 方式消耗并且lot 在 batch 出站时进行消耗计算,通过batchFlag标记已经消耗过了
                            equipmentBom.setBatchFlag(true);
                            consumeQty += 1;
                        }
                    }
                }
                totalQuantity = totalQuantity - consumeQty;
                Assert.isFalse(totalQuantity < 0,
                               Errors.create().key(MessageIdList.BOM_INVENTORY_NOT_ENOUGH).args(totalQuantity).build());
                map.put("batchId", batchId);
                map.put("consumeType", consumeType);
                map.put("consumeMode", consumeMode);
                //insert consume
                consumeMaterialFromWarehouseForBom(material, consumeQty, map);
            }
        }
    }

    private void saveReceivedMaterialToWarehouse(LotInventoryDO lotInventory,
                                                 InventoryTransHistoryDO inventoryTransHistory) {
        materialManager.saveMaterialForReceived(inventoryTransHistory);

        saveWarehouseForReceived(inventoryTransHistory);

        saveLotInventoryForReceived(lotInventory, inventoryTransHistory);
    }

    private void saveLotInventoryForReceived(LotInventoryDO lotInventory,
                                             InventoryTransHistoryDO inventoryTransHistory) {
        lotInventoryManager.saveLotInventory(lotInventory);
        insertInventoryTransHistory(inventoryTransHistory);
    }

    private void insertInventoryTransHistory(InventoryTransHistoryDO inventoryTransHistory) {
        warehouseDAO.insertInventoryTransHistory(inventoryTransHistory);
        warehouseDAO.insertInventoryTransHistoryExt(inventoryTransHistory);
    }

    private void saveWarehouseForReceived(InventoryTransHistoryDO inventoryTransHistory) {
        Boolean isExisted = warehouseDAO.checkMaterialIsExistedInWarehouse(inventoryTransHistory.getWarehouseRrn(),
                                                                           inventoryTransHistory.getItemRrn());
        if (isExisted) {
            warehouseDAO.updateWarehouseInventoryForReceiptQty(inventoryTransHistory.getWarehouseRrn(),
                                                               inventoryTransHistory.getItemRrn(),
                                                               inventoryTransHistory.getTransQty());
        } else {
            warehouseDAO.insertWarehouseInventory(buildWarehouseInventoryForInsert(inventoryTransHistory));
        }
        warehouseDAO.insertWarehouseInventoryHistory(inventoryTransHistory.getWarehouseRrn(),
                                                     inventoryTransHistory.getItemRrn(),
                                                     inventoryTransHistory.getTransRrn(),
                                                     inventoryTransHistory.getTransSequence(),
                                                     inventoryTransHistory.getTransQty());
    }

    private WarehouseInventoryDO buildWarehouseInventoryForInsert(InventoryTransHistoryDO inventoryTransHistory) {
        WarehouseInventoryDO warehouseInventory = new WarehouseInventoryDO();
        warehouseInventory.setItemRrn(inventoryTransHistory.getItemRrn());
        warehouseInventory.setWarehouseRrn(inventoryTransHistory.getWarehouseRrn());
        warehouseInventory.setWarehouseId(inventoryTransHistory.getWarehouseId());
        warehouseInventory.setReceiptQty(inventoryTransHistory.getTransQty());
        warehouseInventory.setIssueQty(0D);
        warehouseInventory.setAdjustQty(0D);
        return warehouseInventory;
    }

    private void setLotInventoryQty(String transId, WarehouseTransBO warehouseTrans) {
        LotInventoryDO lotInventory = warehouseTrans.getLotInventoryDO();

        if (TransactionNames.RECEIVE_KEY.equals(transId)) {
            lotInventory.setReceiptQty(warehouseTrans.getTransQty());
            lotInventory.setIssueQty(0D);
            lotInventory.setAdjustQty(0D);
        } else if (TransactionNames.ADJUST_KEY.equals(transId)) {
            lotInventory.setReceiptQty(0D);
            lotInventory.setIssueQty(0D);
            lotInventory.setAdjustQty(warehouseTrans.getTransQty());
        } else {
            lotInventory.setReceiptQty(0D);
            lotInventory.setIssueQty(warehouseTrans.getTransQty());
            lotInventory.setAdjustQty(0D);
        }
    }

    /**
     * 构建库存事务历史信息
     *
     * @param facilityRrn
     * @param warehouseTrans
     * @param transactionLog
     * @param transSequence
     * @return
     */
    private InventoryTransHistoryDO buildInventoryTransHistory(Long facilityRrn, WarehouseTransBO warehouseTrans,
                                                               TransactionLog transactionLog, Long transSequence) {
        InventoryTransHistoryDO inventoryTransHistory = new InventoryTransHistoryDO();

        // Transaction info
        inventoryTransHistory.setTransRrn(transactionLog.getTransRrn());
        inventoryTransHistory.setTransSequence(transSequence);
        inventoryTransHistory.setTransId(transactionLog.getTransId());
        inventoryTransHistory.setTransQty(Math.abs(warehouseTrans.getTransQty()));
        inventoryTransHistory.setTransDate(transactionLog.getTransStartTimestamp());

        // lotInventory info
        inventoryTransHistory.setFacilityRrn(facilityRrn);
        inventoryTransHistory.setWarehouseId(warehouseTrans.getLotInventoryDO().getWarehouseId());
        inventoryTransHistory.setWarehouseRrn(warehouseTrans.getLotInventoryDO().getWarehouseRrn());
        inventoryTransHistory.setItemRrn(warehouseTrans.getLotInventoryDO().getItemRrn());
        inventoryTransHistory.setMaterialLotNumber(warehouseTrans.getLotInventoryDO().getLotNumber());
        inventoryTransHistory.setComments(warehouseTrans.getTransComments());

        return inventoryTransHistory;
    }

    private void saveConsumeMaterialFromWarehouse(LotInventoryDO lotInventory,
                                                  InventoryTransHistoryDO inventoryTransHistory) {
        materialManager.saveMaterialForConsumed(inventoryTransHistory);

        saveWarehouseForConsumed(inventoryTransHistory);

        saveLotInventoryForConsumed(lotInventory, inventoryTransHistory);
    }

    private void saveWarehouseForConsumed(InventoryTransHistoryDO inventoryTransHistory) {
        warehouseDAO.updateWarehouseInventoryForIssueQty(inventoryTransHistory.getWarehouseRrn(),
                                                         inventoryTransHistory.getItemRrn(),
                                                         inventoryTransHistory.getTransQty());
        warehouseDAO.insertWarehouseInventoryHistory(inventoryTransHistory.getWarehouseRrn(),
                                                     inventoryTransHistory.getItemRrn(),
                                                     inventoryTransHistory.getTransRrn(),
                                                     inventoryTransHistory.getTransSequence(),
                                                     inventoryTransHistory.getTransQty());
    }

    private void saveLotInventoryForConsumed(LotInventoryDO lotInventory,
                                             InventoryTransHistoryDO inventoryTransHistory) {
        lotInventoryManager.updateLotInventoryForQty(lotInventory);

        insertInventoryTransHistory(inventoryTransHistory);
    }

    private void saveStocktakeMaterialFromWarehouse(LotInventoryDO lotInventory,
                                                    InventoryTransHistoryDO inventoryTransHistory) {
        materialManager.saveMaterialForStocktake(inventoryTransHistory);

        saveWarehouseForStocktake(inventoryTransHistory);

        saveLotInventoryForStocktake(lotInventory, inventoryTransHistory);
    }

    private void saveWarehouseForStocktake(InventoryTransHistoryDO inventoryTransHistory) {
        warehouseDAO.updateWarehouseInventoryForAdjustQty(inventoryTransHistory.getWarehouseRrn(),
                                                          inventoryTransHistory.getItemRrn(),
                                                          inventoryTransHistory.getTransQty());
        warehouseDAO.insertWarehouseInventoryHistory(inventoryTransHistory.getWarehouseRrn(),
                                                     inventoryTransHistory.getItemRrn(),
                                                     inventoryTransHistory.getTransRrn(),
                                                     inventoryTransHistory.getTransSequence(),
                                                     inventoryTransHistory.getTransQty());
    }

    private void saveLotInventoryForStocktake(LotInventoryDO lotInventory,
                                              InventoryTransHistoryDO inventoryTransHistory) {
        lotInventoryManager.updateLotInventoryForQty(lotInventory);

        insertInventoryTransHistory(inventoryTransHistory);
    }

    private void insertLotConsumesMaterialHistory(LotConsumesMaterialHistory lotConsumesMaterialHistory) {
        lotInventoryManager.insertLotConsumesMaterialHistory(lotConsumesMaterialHistory);
    }

    private LotStepBomHistoryDO buildLotStepBom(InventoryTransHistoryDO inventoryTransHistory, Map map) {
        LotStepBomHistoryDO lotStepBomHistoryDO = new LotStepBomHistoryDO();
        lotStepBomHistoryDO.setTransRrn(inventoryTransHistory.getTransRrn());
        lotStepBomHistoryDO.setTransId(inventoryTransHistory.getTransId());
        lotStepBomHistoryDO.setBomConsumeMode(MapUtils.getString(map, "consumeMode"));
        lotStepBomHistoryDO.setBomConsumeType(MapUtils.getString(map, "consumeType"));
        lotStepBomHistoryDO.setComments(inventoryTransHistory.getComments());
        lotStepBomHistoryDO.setItemRrn(inventoryTransHistory.getItemRrn());
        lotStepBomHistoryDO.setLotRrn(inventoryTransHistory.getLotRrn());
        lotStepBomHistoryDO.setBatchId(inventoryTransHistory.getBatchId());
        lotStepBomHistoryDO.setFacilityRrn(LocalContext.getFacilityRrn());
        lotStepBomHistoryDO.setStepSequence(inventoryTransHistory.getStepSequence());
        lotStepBomHistoryDO.setMaterialLotNumber(inventoryTransHistory.getMaterialLotNumber());
        lotStepBomHistoryDO.setWarehouseId(inventoryTransHistory.getWarehouseId());
        lotStepBomHistoryDO.setWarehouseRrn(inventoryTransHistory.getWarehouseRrn());
        lotStepBomHistoryDO.setTransTime(inventoryTransHistory.getTransDate());
        lotStepBomHistoryDO.setTransQty(inventoryTransHistory.getTransQty());
        lotStepBomHistoryDO.setTransSequence(inventoryTransHistory.getTransSequence());
        return lotStepBomHistoryDO;
    }

}