# WorkOrderManagerImpl.java

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

    import com.fa.sesa.exception.Assert;
    import com.fa.sesa.exception.Errors;
    import com.fa.sesa.exception.SystemIllegalArgumentException;
    import com.fa.sesa.threadlocal.LocalContext;
    import com.mycim.framework.jdbc.Page;
    import com.mycim.framework.oid.IDGenerators;
    import com.mycim.framework.oid.type.IDNames;
    import com.mycim.framework.oid.type.SequenceNames;
    import com.mycim.framework.utils.beans.BeanUtils;
    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.framework.utils.lang.time.DateUtils;
    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.prp.manager.OperationManager;
    import com.mycim.server.system.manager.ReferenceFileManager;
    import com.mycim.server.workorder.dao.WorkOrderDao;
    import com.mycim.server.workorder.manager.WorkOrderManager;
    import com.mycim.valueobject.ObjectList;
    import com.mycim.valueobject.bas.NamedObject;
    import com.mycim.valueobject.bas.TransactionLog;
    import com.mycim.valueobject.consts.AsmConst;
    import com.mycim.valueobject.consts.ReferenceDetailNames;
    import com.mycim.valueobject.consts.ReferenceFileConst;
    import com.mycim.valueobject.consts.TransactionNames;
    import com.mycim.valueobject.erp.workOrder.SdsWorkOrderInfo;
    import com.mycim.valueobject.erp.workOrder.SdsWorkOrderMaterialInfo;
    import com.mycim.valueobject.erp.workOrder.WorkOrderImpSourceWaferDb;
    import com.mycim.valueobject.inv.LotInventoryDO;
    import com.mycim.valueobject.inv.MaterialDO;
    import com.mycim.valueobject.inv.WarehouseTransBO;
    import com.mycim.valueobject.inv.value.WarehouseNames;
    import com.mycim.valueobject.prp.Operation;
    import com.mycim.valueobject.prp.WorkOrder;
    import com.mycim.valueobject.prp.WorkOrderLine;
    import com.mycim.valueobject.wip.Lot;
    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.*;
    import java.util.Map.Entry;
    import java.util.stream.Collectors;

    @Service
    @Transactional
    public class WorkOrderManagerImpl implements WorkOrderManager {

        @Autowired
        private WorkOrderDao workOrderDao;

        @Autowired
        private TransactionLogManager transactionLogManager;

        @Autowired
        private NamedObjectManager objectManager;

        @Autowired
        private MaterialManager materialManager;

        @Autowired
        private NamedObjectManager namedObjectManager;

        @Autowired
        private ReferenceFileManager referenceFileManager;

        @Autowired
        private WarehouseManager warehouseManager;

        @Autowired
        private OperationManager operationManager;

        @Override
        public WorkOrder getWorkOrderById(String orderId) {
            return workOrderDao.getWorkOrderById(orderId);
        }

        @Override
        public WorkOrder insertWorkOrder(WorkOrder workOrder) {

            TransactionLog transactionLog = transactionLogManager
                    .startTransactionLog(workOrder.getTransPerformedby(), workOrder.getTransId());
            long transRrn = transactionLog.getTransRrn();
            long objectRrn = objectManager.insertNamedObject(workOrder, transRrn);

            workOrder.setWorkorderRrn(objectRrn);
            workOrder.setCreatedUserId(workOrder.getCreateUser());// 创建者
            workOrder.setStatus("ACTIVE");
            workOrder.setComments(workOrder.getComments());
            workOrderDao.insertWorkOrder(workOrder);

            List<WorkOrderLine> workOrderLines = workOrder.getWorkOrderLines();

            if (CollectionUtils.isNotEmpty(workOrderLines)) {
                for (WorkOrderLine workOrderLine : workOrderLines) {
                    Long workOrderLineRrn = Long
                            .parseLong(IDGenerators.get(IDNames.SEQUENCE).generateId(SequenceNames.MODULE_SEQ_OBJECT_RRN));
                    workOrderLine.setWorkorderLineRrn(workOrderLineRrn);
                    workOrderLine.setWorkorderRrn(workOrder.getWorkorderRrn());
                }

                workOrderDao.insertWorkOrderLines(workOrderLines);
            }

            return workOrder;
        }

        @Override
        public void updateWorkOrder(WorkOrder workOrder) {
            workOrderDao.updateWorkOrder(workOrder);
        }

        @Override
        public List<WorkOrder> getWorkOrderByIdLike(String orderId) {
            return workOrderDao.getWorkOrderByIdLike(orderId);
        }

        @Override
        public Page getWorkOrderImpDBByOrderRrn(Page page, long orderRrn) {
            return workOrderDao.getWorkOrderImpDBByOrderRrn(page, orderRrn);
        }

        @Override
        public WorkOrderImpSourceWaferDb getImportWkByImpRrn(String importRrn) {
            return workOrderDao.getImportWkByImpRrn(importRrn);
        }

        @Override
        public WorkOrder getWorkOrderByRrn(Long workOrderRrn) {
            return workOrderDao.getWorkOrderByRrn(workOrderRrn);
        }

        @Override
        public List<WorkOrder> getWorkOrderByCondition(Map<String, Object> condition) {
            return workOrderDao.getWorkOrderByCondition(condition);
        }

        @Override
        public void workOrderImpCreateLotSuccess(List<WorkOrderImpSourceWaferDb> list, Lot lot, Long workOrderRrn) {
            String carrierId = objectManager.getInstanceId(lot.getCarrierRrn());
            for (WorkOrderImpSourceWaferDb db : list) {
                db.setLotRrn(lot.getLotRrn());
                db.setLotId(lot.getLotId());
                db.setCarrierRrn(lot.getCarrierRrn());
                db.setCarrierId(carrierId);
            }
            workOrderDao.workOrderImpCreateLotSuccess(list);
            //对比完成数量，更改workorder状态
            //package完成后才算完成
    		/*int compleWf = workOrderDao.getCompleteDieQtyByWorkOrderRrn(workOrderRrn);
    		WorkOrder workOrderByRrn = workOrderDao.getWorkOrderByRrn(workOrderRrn);
    		if(compleWf >= workOrderByRrn.getOrderDieQty()) {
    			workOrderDao.completeWorkOrder(workOrderRrn);
    		}*/

        }

        @Override
        public int getCompleteDieQtyByWorkOrderRrn(Long workOrderRrn) {
            return workOrderDao.getCompleteDieQtyByWorkOrderRrn(workOrderRrn);
        }

        @Override
        public void completeWorkOrder(Long workOrderRrn) {
            workOrderDao.completeWorkOrder(workOrderRrn);
        }

        @Override
        public List<String> getMesProductIdBySdsProductId(String sdsProductId) {
            return workOrderDao.getMesProductIdBySdsProductId(sdsProductId);
        }

        @Override
        public boolean checkMesProSdsProMapping(String productId, String sdsProductId) {
            return workOrderDao.checkMesProSdsProMapping(productId, sdsProductId);
        }

        @Override
        public void insertProductMapping(String productId, String sdsProductId, String userId) {
            Assert.isFalse(checkMesProSdsProMapping(productId, sdsProductId),
                           Errors.create().content("{} mapping to {} exists!").build());
            workOrderDao.insertProductMapping(productId, sdsProductId, userId);
        }

        @Override
        public List<SdsWorkOrderInfo> getSdsWorkOrderInfoByWorkOrderId(String workorderId) {
            return workOrderDao.getSdsWorkOrderInfoByWorkOrderId(workorderId);
        }

        @Override
        public List<Map> getSdsMesMappingInfoByProductId(String productId) {
            return workOrderDao.getSdsMesMappingInfoByProductId(productId);
        }

        @Override
        public boolean checkAreadySdsProReceive(String deleteProductMapping) {
            int count = workOrderDao.getAreadySdsProReceiveCount(deleteProductMapping);
            if (count > 0) {
                return true;
            } else {
                return false;
            }
        }

        @Override
        public void deleteProductMapping(String mesproduct, String sdsproduct) {
            workOrderDao.deleteProductMapping(mesproduct, sdsproduct);
        }

        @Override
        public List<SdsWorkOrderMaterialInfo> getSdsMaterialInfoByWorkOrderId(long workorderRrn) {
            return workOrderDao.getSdsMaterialInfoByWorkOrderId(workorderRrn);
        }

        @Override
        public void mappingReceive(List<HashMap> workorderIds) {
            if (CollectionUtils.isNotEmpty(workorderIds)) {
                Set<WorkOrderImpSourceWaferDb> dataSet = new HashSet<WorkOrderImpSourceWaferDb>();
                for (HashMap workorderMap : workorderIds) {
                    String workorderId = MapUtils.getString(workorderMap, "workorderId");
                    String mesProduct = MapUtils.getString(workorderMap, "mesProduct");
                    long workorderRrn = MapUtils.getLong(workorderMap, "workorderRrn", 0L);
                    checkReceiveList(dataSet, workorderRrn, workorderId, mesProduct);
                }
                List<WorkOrderImpSourceWaferDb> dataList = new ArrayList<WorkOrderImpSourceWaferDb>(dataSet);
                storeMaterInfo(dataList);
                workOrderDao.storeWorkOrderImpDBList(dataList);
            }
        }

        @Override
        public void addShipQty4WorkOrder(WorkOrder workOrder, int qty) {
            TransactionLog transactionLog = transactionLogManager
                    .startTransactionLog(workOrder.getTransPerformedby(), TransactionNames.ADD_WO_SHIPQTY);

            Integer shippedQty = workOrder.getShippedQty() == null ? 0 : workOrder.getShippedQty();

            workOrderDao.updateShipQty4WorkOrder(workOrder.getWorkorderRrn(), shippedQty + qty);

            transactionLogManager.markTransactionLog(transactionLog);
        }

        @Override
        public int getWorkorderAvalibleShipQty(String workorderId) {
            WorkOrder workOrder = this.getWorkOrderById(workorderId);

            Integer planQty = workOrder.getPlannedYield() == null ? 0 : workOrder.getPlannedYield();
            Integer shippedQty = workOrder.getShippedQty() == null ? 0 : workOrder.getShippedQty();

            return planQty - shippedQty;
        }

        @Override
        public void addStartQty4WorkOrder(WorkOrder workOrder, int qty) {
            TransactionLog transactionLog = transactionLogManager
                    .startTransactionLog(workOrder.getTransPerformedby(), TransactionNames.ADD_WO_STARTQTY);

            Integer startQty = workOrder.getStartQty() == null ? 0 : workOrder.getStartQty();

            workOrderDao.updateStartQty4WorkOrder(workOrder.getWorkorderRrn(), startQty + qty);

            transactionLogManager.markTransactionLog(transactionLog);

        }

        @Override
        public int getWorkorderAvalibleStartQty(String workorderId) {
            WorkOrder workOrder = this.getWorkOrderById(workorderId);

            Integer planQty = workOrder.getPlannedYield() == null ? 0 : workOrder.getPlannedYield();
            Integer startQty = workOrder.getShippedQty() == null ? 0 : workOrder.getStartQty();

            return planQty - startQty;
        }

        private void checkReceiveList(Set<WorkOrderImpSourceWaferDb> dataList, long sdsWorkorderRrn, String sdsworkorderId,
                                      String mesProductId) {
            //检查fabid
            long fab_rrn = LocalContext.getFacilityRrn();
            // 根据workorderid 获取sds workorder info 一条数据
            SdsWorkOrderInfo sdsWorkOrderInfo = workOrderDao.getNotReceiveSdsWorkOrderByWorkOrderRrn(sdsWorkorderRrn);
            Assert.notNull(sdsWorkOrderInfo, Errors.create().content("workOrder error: {}").args(sdsworkorderId).build());
            // sds product 与mes product 映射校验
            Assert.isFalse(StringUtils.isBlank(mesProductId), Errors.create().content(
                    "MESPRODUCT-SDSPRODUCT mapping not " + "exists：workorderId:{} ,SDSPRODUCT:{}")
                                                                    .args(sdsworkorderId, sdsWorkOrderInfo.getSdsProduct())
                                                                    .build());
            NamedObject product = namedObjectManager
                    .getNamedObject(mesProductId, LocalContext.getFacilityRrn(), ObjectList.PRODUCT_KEY);
            Assert.isFalse(product == null || product.getInstanceRrn() == 0L,
                           Errors.create().content("productId not exist: {}").args(mesProductId).build());

            //改变t_sds_workorder_info 表中receive_status 状态，修正为1，则表示已重新接收
            workOrderDao.updateProductMappingStatus(sdsWorkOrderInfo.getWorkorderRrn(), "1");
            WorkOrder workOrder = getWorkOrderById(sdsWorkOrderInfo.getWorkorderId());
            if (workOrder == null) {
                workOrder = new WorkOrder();
                workOrder.setWorkorderId(sdsWorkOrderInfo.getWorkorderId());
                workOrder.setObject(ObjectList.WORKORDER);
                workOrder.setNamedSpace(namedObjectManager.getNamedSpace(fab_rrn, ObjectList.WORKORDER));
                workOrder.setInstanceId(sdsWorkOrderInfo.getWorkorderId());
                workOrder.setTransPerformedby(LocalContext.getUserId());
                workOrder.setTransId("CREATE");

                workOrder.setWorkorderPriority(sdsWorkOrderInfo.getWorkorderPriority());
                workOrder.setProductId(mesProductId);
                workOrder.setOrderDieQty(sdsWorkOrderInfo.getOrderDieQty());
                workOrder.setStartDay(StringUtils.isEmpty(sdsWorkOrderInfo.getStartDayStr()) ? null : new Timestamp(
                        DateUtils.parse(sdsWorkOrderInfo.getStartDayStr(), DateUtils.DATE_FORMAT4DAY).getTime()));
                workOrder.setRequireDay(StringUtils.isEmpty(sdsWorkOrderInfo.getRequireDayStr()) ? null : new Timestamp(
                        DateUtils.parse(sdsWorkOrderInfo.getRequireDayStr(), DateUtils.DATE_FORMAT4DAY).getTime()));
                workOrder.setDayDay(StringUtils.isEmpty(sdsWorkOrderInfo.getDayStr()) ? null : new Timestamp(
                        DateUtils.parse(sdsWorkOrderInfo.getDayStr(), DateUtils.DATE_FORMAT4DAY).getTime()));
                workOrder.setDueDate(StringUtils.isEmpty(sdsWorkOrderInfo.getDueDateStr()) ? null : new Timestamp(
                        DateUtils.parse(sdsWorkOrderInfo.getDueDateStr(), DateUtils.DATE_FORMAT4DAY).getTime()));
                workOrder = insertWorkOrder(workOrder);
            } else {
                String productId = workOrder.getProductId();
                if (StringUtils.isEmpty(productId)) {
                    workOrder.setProductId(mesProductId);
                    updateWorkOrder(workOrder);
                } else if (StringUtils.isNotEmpty(productId) && !StringUtils.equals(mesProductId, productId)) {
                    throw new SystemIllegalArgumentException(Errors.create().content("Sds product miss match").build());
                }
            }

            //获取source wafer 信息
            List<SdsWorkOrderMaterialInfo> sourceWafer = workOrderDao
                    .getSdsWorkOrderMaterialInfoByWorkOrderRrn(sdsWorkOrderInfo.getWorkorderRrn());
            //sds可能在设置mapping对应前传多次，需要根据wafer号去除已经有的
            List<String> workOrderImpWaferByWaferId = workOrderDao.getWorkOrderImpWaferByWaferId(
                    sourceWafer.stream().map(sdsMInfo -> sdsMInfo.getSourceWaferId()).collect(Collectors.toList()));

            for (SdsWorkOrderMaterialInfo sdsWorkOrderMaterialInfo : sourceWafer) {
                if (workOrderImpWaferByWaferId.contains(sdsWorkOrderMaterialInfo.getSourceWaferId())) {
                    continue;
                }
                WorkOrderImpSourceWaferDb db = new WorkOrderImpSourceWaferDb();
                BeanUtils.copyProperties(sdsWorkOrderMaterialInfo, db);
                db.setSdsProduct(sdsWorkOrderInfo.getSdsProduct());
                db.setUniqueNum(db.getSourceWaferId());
                db.setWorkorderRrn(workOrder.getWorkorderRrn());
                db.setStatus(WorkOrderImpSourceWaferDb.ACTIVE);
                dataList.add(db);
            }
        }

        private void storeMaterInfo(List<WorkOrderImpSourceWaferDb> dataList) {
            long facilityRrn = LocalContext.getFacilityRrn();
            Operation warehouse = operationManager.getOperation("WAFER_BANK", facilityRrn);
            Map<String, List<WorkOrderImpSourceWaferDb>> materMapList = dataList.stream().collect(
                    Collectors.groupingBy(db -> db.getMaterialId()));

            for (Entry<String, List<WorkOrderImpSourceWaferDb>> entrySet : materMapList.entrySet()) {
                MaterialDO material = new MaterialDO(entrySet.getKey(),
                                                     namedObjectManager.getNamedSpace(facilityRrn, ObjectList.ITEM_KEY),
                                                     ObjectList.ITEM_KEY);
                material = materialManager.getMaterial(material);
                if (material == null || material.getInstanceRrn() < 1) {
                    material = new MaterialDO(entrySet.getKey(),
                                              namedObjectManager.getNamedSpace(facilityRrn, ObjectList.ITEM_KEY),
                                              ObjectList.ITEM_KEY);
                    material.setExpirationLength(28);
                    material.setObjectType("MATERIAL");
                    material.setObjectSubtype("WAFER");
                    material.setTransId("create");
                    materialManager.insertMaterial(material);
                    material = materialManager.getMaterial(material);
                }

                String refFileValue = referenceFileManager
                        .getRefFileValue(ReferenceDetailNames.UNIT_OF_MEASURE_FOR_BANK, material.getStoreUom(),
                                         ReferenceFileConst.DATA_1_VALUE);
                Map<String, List<WorkOrderImpSourceWaferDb>> materLotMapList = entrySet.getValue().stream().collect(
                        Collectors.groupingBy(db -> db.getMaterialLotNum()));
                List<Map<String, String>> receiptList = new ArrayList<Map<String, String>>();
                for (Entry<String, List<WorkOrderImpSourceWaferDb>> entryLot : materLotMapList.entrySet()) {
                    String materLotNum = entryLot.getKey();
                    Integer count = entryLot.getValue().size();

                    Map<String, String> result = new HashMap<>();
                    result.put(AsmConst.MATERIAL_RRN, Long.toString(material.getInstanceRrn()));
                    result.put(AsmConst.MATERIAL_ID, material.getInstanceId());
                    result.put(AsmConst.MATERIAL_DESC,
                               material.getInstanceDesc() == null ? "" : material.getInstanceDesc());
                    result.put(AsmConst.LOT_NUMBER, materLotNum);
                    result.put(AsmConst.QTY, count.toString());
                    result.put(AsmConst.STORE_UOM, StringUtils.trimToEmpty(refFileValue));
    				/*result.put(AsmConst.SUPPLIER_ID, theform.getSupplierId());
    				result.put(AsmConst.MANUFACTURER_ID, theform.getManufacturerId());
    				result.put(AsmConst.EXPIRATION_DATE, theform.getExpirationDate());
    				result.put(AsmConst.PRODUCTION_DATE, theform.getProductionDate());
    				result.put(AsmConst.INCOMING_DATE, theform.getIncomingDate());
    				result.put(AsmConst.CHECK_DATE, theform.getCheckDate());
    				result.put(AsmConst.CHECK_USER, userInfo);
    				result.put(AsmConst.CHECK_RESULT, theform.getCheckResult());
    				result.put(AsmConst.COMMENTS, theform.getComments());*/
                    receiptList.add(result);
                }
                List<WarehouseTransBO> receiveTrans = new ArrayList<>();
                WarehouseTransBO warehouseTrans;

                for (Map<String, String> map : receiptList) {
                    warehouseTrans = new WarehouseTransBO();
                    buildWarehouseTrans(warehouseTrans, warehouse, material, map);

                    receiveTrans.add(warehouseTrans);
                }

                warehouseManager.saveReceivedMaterialToWarehouse(facilityRrn, "ERP", receiveTrans);

            }

        }

        private void buildWarehouseTrans(WarehouseTransBO warehouseTrans, Operation warehouse, MaterialDO material,
                                         Map<String, String> map) {
            warehouseTrans.setTransQty(NumberUtils.toDouble(MapUtils.getString(map, AsmConst.QTY)));
            warehouseTrans.setTransComments(MapUtils.getString(map, AsmConst.COMMENTS));

            LotInventoryDO lotInventory = warehouseTrans.getLotInventoryDO();

            lotInventory.setLotNumber(MapUtils.getString(map, AsmConst.LOT_NUMBER));
            lotInventory.setItemRrn(material.getInstanceRrn());
            lotInventory.setWarehouseRrn(warehouse.getInstanceRrn());
            lotInventory.setWarehouseId(warehouse.getInstanceId());
            lotInventory.setMaterialType(material.getObjectSubtype());

            lotInventory.setReceiptDate(new Timestamp(System.currentTimeMillis()));
            lotInventory.setExpirationDate(DateUtils.stringToTimestamp(MapUtils.getString(map, AsmConst.EXPIRATION_DATE)));
            lotInventory.setProductionDate(DateUtils.stringToTimestamp(MapUtils.getString(map, AsmConst.PRODUCTION_DATE)));
            lotInventory.setIncomingDate(DateUtils.stringToTimestamp(MapUtils.getString(map, AsmConst.INCOMING_DATE)));
            lotInventory.setCheckDate(DateUtils.stringToTimestamp(MapUtils.getString(map, AsmConst.CHECK_DATE)));
            lotInventory.setCheckUser(MapUtils.getString(map, AsmConst.CHECK_USER));
            lotInventory.setCheckResult(MapUtils.getString(map, AsmConst.CHECK_RESULT));

            warehouseManager.setExpirationDateForReceive(material.getExpirationLength(), lotInventory);

            lotInventory.setAttributeData1(MapUtils.getString(map, AsmConst.SUPPLIER_ID));
            lotInventory.setAttributeData2(MapUtils.getString(map, AsmConst.MANUFACTURER_ID));

            lotInventory.setStatus(WarehouseNames.ACTIVE_STATUS);
        }
    }