# OcapQueryManagerImpl.java

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

    import com.fa.sesa.exception.Assert;
    import com.fa.sesa.exception.Errors;
    import com.mycim.framework.jdbc.Page;
    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.time.DateUtils;
    import com.mycim.framework.utils.msg.JsonUtils;
    import com.mycim.framework.workflow.engine.WorkflowManagerService;
    import com.mycim.server.base.manager.NamedObjectManager;
    import com.mycim.server.ems.manager.EntityManager;
    import com.mycim.server.prp.manager.WorkflowManager;
    import com.mycim.server.wip.dao.OcapQueryDAO;
    import com.mycim.server.wip.manager.EquipmentQueryManager;
    import com.mycim.server.wip.manager.LotQueryManager;
    import com.mycim.server.wip.manager.OcapQueryManager;
    import com.mycim.server.wip.manager.UnitQueryManager;
    import com.mycim.utils.GenerateOCAPIdUtil;
    import com.mycim.utils.OcapUtil;
    import com.mycim.valueobject.ObjectList;
    import com.mycim.valueobject.consts.ActionIdEnum;
    import com.mycim.valueobject.consts.EventName;
    import com.mycim.valueobject.consts.OcapTypeEnum;
    import com.mycim.valueobject.consts.VersionStatus;
    import com.mycim.valueobject.ocap.OcapCard;
    import com.mycim.valueobject.ocap.OcapStepOwner;
    import com.mycim.valueobject.ocap.OcapTransData;
    import com.mycim.valueobject.ocap.OcapTransLog;
    import com.mycim.valueobject.ocap.dto.*;
    import com.mycim.valueobject.wip.Lot;
    import com.mycim.workflow.valueobject.WorkflowInstance;
    import com.mycim.workflow.valueobject.WorkflowPath;
    import com.mycim.workflow.valueobject.WorkflowStepModel;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.util.*;
    import java.util.stream.Collectors;

    /**
     * @author songpy
     * @version 1.0.0
     * @date 2021/1/21
     **/
    @Service
    @Transactional
    public class OcapQueryManagerImpl implements OcapQueryManager {

        @Autowired
        OcapQueryDAO queryDAO;

        @Autowired
        EquipmentQueryManager equipmentQueryManager;

        @Autowired
        NamedObjectManager namedObjectManager;

        @Autowired
        UnitQueryManager unitQueryManager;

        @Autowired
        WorkflowManagerService workflowManagerService;

        @Autowired
        WorkflowManager workflowManager;

        @Autowired
        LotQueryManager lotQueryManager;

        @Autowired
        EntityManager entityManager;

        @Override
        public List<Map<String, String>> getWorkflowIdOptions() {
            List<Map<String, String>> results = new ArrayList<>();

            List<String> workflowIds = queryDAO.getWorkflowIds();
            for (String workflowId : workflowIds) {
                Map<String, String> map = new HashMap<>();

                map.put("key", workflowId);
                map.put("value", workflowId);

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

        @Override
        public Page getOcapCardPage(OcapQueryConditionDTO queryConditionDTO) {
            Page page = new Page(queryConditionDTO.getPage(), queryConditionDTO.getLimit());
            queryConditionDTO.setStartTime(DateUtils.stringToTimestamp(queryConditionDTO.getStartDate()));
            queryConditionDTO.setEndTime(DateUtils.stringToTimestamp(queryConditionDTO.getEndDate() + " 24:00:00"));
            return queryDAO.getOcapCardPage(page, queryConditionDTO);
        }

        @Override
        public void checkActiveOfflineOcapId(Long facilityRrn, String equipmentId, String chartName) {
            long equipmentRrn = namedObjectManager.getNamedObjectRrn(equipmentId, facilityRrn, ObjectList.ENTITY_KEY);
            String ocapId = getActiveOfflineOcapId(equipmentRrn, chartName);
            Assert.isFalse(StringUtils.isNotEmpty(ocapId), Errors.create().content(
                    "This equipment and chart have OCAP: {}, and the" + " specified action of the current review" + " " +
                            "step is empty or not supported. " + "Check, please.").args(ocapId).build());
        }

        @Override
        public void checkActiveInlineOcapId(Long lotRrn) {
            Assert.isFalse(StringUtils.isNotEmpty(getActiveInlineOcapId(lotRrn)),
                           Errors.create().content("Lot has valid OCAP. " + "Cannot do action.").build());
        }

        @Override
        public String getActiveOfflineOcapId(Long equipmentRrn, String chartName) {
            List<String> ocapIds = queryDAO.getOcapIds(equipmentRrn, chartName, OcapTypeEnum.OFFLINE.toString(),
                                                       VersionStatus.ACTIVE_KEY);
            if (CollectionUtils.isEmpty(ocapIds)) {
                return StringUtils.EMPTY;
            }
            return ocapIds.get(0);
        }

        @Override
        public String getMaxOcapIdOfToday(String planIdPattern) {
            return queryDAO.getMaxOcapIdOfToday(planIdPattern + GenerateOCAPIdUtil.SUFFIX_PLACEHOLDER);
        }

        @Override
        public OcapCard getOcapCardByUniqueKey(Long facilityRrn, String ocapId, String lotId) {
            return queryDAO.getOcapCardByUniqueKey(facilityRrn, ocapId, lotId);
        }

        @Override
        public List<OcapCard> getOcapCardsByBatch(Long facilityRrn, OcapCard ocap) {
            List<OcapCard> ocapCards = new ArrayList<OcapCard>();
            if (StringUtils.isNotEmpty(ocap.getOcapBatchId())) {
                ocapCards = queryDAO.getOcapCardsByBatchId(facilityRrn, ocap.getOcapBatchId());
                if (CollectionUtils.isEmpty(ocapCards)) {
                    return new ArrayList<OcapCard>();
                }
            } else {
                ocapCards.add(ocap);
            }

            return ocapCards;
        }

        @Override
        public boolean hasActiveOfflineOcapCardIds(Long equipmentRrn) {
            return CollectionUtils.isNotEmpty(getActiveOfflineOcapIdsByProcessEquipment(equipmentRrn));
        }

        @Override
        public String getActiveInlineOcapId(Long lotRrn) {
            List<String> planIds = queryDAO.getOcapIds(lotRrn, OcapTypeEnum.INLINE.toString(), VersionStatus.ACTIVE_KEY);
            if (CollectionUtils.isEmpty(planIds)) {
                return StringUtils.EMPTY;
            }
            return planIds.get(0);
        }

        @Override
        public Long getOcapCardRrnByUniqueKey(Long facilityRrn, String ocapId, String lotId) {
            OcapCard ocap = getOcapCardByUniqueKey(facilityRrn, ocapId, lotId);
            if (ocap == null) {
                return null;
            }
            return ocap.getOcapRrn();
        }

        @Override
        public List<String> getActiveOfflineOcapIds(Long eqptRrn) {
            return getActiveOfflineOcapIdsByProcessEquipment(eqptRrn);
        }

        @Override
        public void checkActiveOfflineOcapId(Long eqptRrn) {
            List<String> ocapIds = getActiveOfflineOcapIdsByProcessEquipment(eqptRrn);
            Assert.isFalse(CollectionUtils.isNotEmpty(ocapIds), Errors.create().content(
                    "Since the equipment has some OCAP IDs, the" + " equipment status cannot be " + "modified. OCAP IDs: " +
                            "{}").args(ocapIds.toString()).build());
        }

        @Override
        public Boolean checkLogEventActiveOfflineOcap(Long eqptRrn, String eventId) {
            List<String> ocapIds = getActiveOfflineOcapIdsByProcessEquipment(eqptRrn);

            if (CollectionUtils.isNotEmpty(ocapIds)) {
                return Arrays.asList(EventName.AVAILABLE_EQP_LOG_EVENT_BY_OFFLINE).contains(eventId);
            }

            return true;
        }

        @Override
        public OcapCard getOcapCardByPrimaryKey(Long ocapRrn) {
            return queryDAO.getOcapCardByPrimaryKey(ocapRrn);
        }

        @Override
        public List<OcapChartInfoDTO> queryOcapChartInfoList(OcapChartInfoDTO dto) {
            return queryDAO.queryOcapChartInfoList(dto);
        }

        @Override
        public List<OcapCard> getOcapCardsByBatchId(Long facilityRrn, String ocapBatchId) {
            return queryDAO.getOcapCardsByBatchId(facilityRrn, ocapBatchId);
        }

        @Override
        public boolean isValidOcapHold(Long lotRrn, String oldReason) {
            String ocapId = getActiveInlineOcapId(lotRrn);
            return StringUtils.isNotEmpty(ocapId) && StringUtils.contains(oldReason, ocapId);
        }

        @Override
        public OcapTransData getTransDataByUniqueKey(Long ocapRrn, String dataName) {
            return queryDAO.getTransDataByUniqueKey(ocapRrn, dataName);
        }

        @Override
        public List<OcapTransData> getTransDatasByOcapRrn(Long ocapRrn) {
            return queryDAO.getTransDatasByOcapRrn(ocapRrn);
        }

        @Override
        public List<OcapTransLog> getTransLogsByOcapRrn(Long ocapRrn) {
            return queryDAO.getTransLogsByOcapRrn(ocapRrn);
        }

        @Override
        public OcapCardDTO getOcapInfo(long facilityRrn, Long ocapRrn) {
            return buildOcapCardDTO(facilityRrn, getOcapCardByPrimaryKey(ocapRrn));
        }

        @Override
        public OcapCardDTO getOcapInfo(Long facilityRrn, String ocapId, String lotId) {
            return buildOcapCardDTO(facilityRrn, getOcapCardByUniqueKey(facilityRrn, ocapId, lotId));
        }

        @Override
        public String getRemeasureUnitIds(Long facilityRrn, Long lotRrn, Long parameterRrn) {
            String remeasureUnitIds = null;
            OcapCardDTO ocap = getOcapInfoByLot(facilityRrn, lotRrn);
            if (ocap != null) {
                String unitIdJson = OcapUtil.getRemeasureUnitIds(ocap.getTransDatas());
                if (StringUtils.isNotEmpty(unitIdJson)) {
                    List<UnitIdDTO> unitIdDTOS = JsonUtils.toList(unitIdJson, UnitIdDTO.class);
                    for (UnitIdDTO unitIdDTO : unitIdDTOS) {
                        if (Objects.nonNull(unitIdDTO.getParameterRrn()) &&
                                unitIdDTO.getParameterRrn().equals(parameterRrn)) {
                            remeasureUnitIds = unitIdDTO.getUnitIds();
                            break;
                        } else if (Objects.isNull(unitIdDTO.getParameterRrn())) { //为空代表为加量
                            remeasureUnitIds = unitIdDTO.getUnitIds();
                            break;
                        }
                    }
                }
            }
            return remeasureUnitIds;
        }

        @Override
        public List<String> getActiveOfflineOcapListByLot(Long lotRrn) {
            List<String> ocapIds = queryDAO.getOcapIds(lotRrn, OcapTypeEnum.OFFLINE.toString(), VersionStatus.ACTIVE_KEY);

            return ocapIds;
        }

        private OcapCardDTO buildOcapCardDTO(Long facilityRrn, OcapCard ocap) {
            OcapCardDTO ocapCardDTO = buildOcapCardDTO(ocap);

            // 构建trans data
            ocapCardDTO.setTransDatas(buildTransDatas(ocapCardDTO.getOcapRrn()));

            // 构建trans log data
            ocapCardDTO.setTransLogs(buildTransLogs(ocapCardDTO.getOcapRrn()));

            // 构建 step，btn 信息
            ocapCardDTO.setStep(buildOcapStep(ocapCardDTO));

            // 构建current step 权限信息
            buildOcapStepOwner(ocapCardDTO);

            if (StringUtils.equals(VersionStatus.ACTIVE_KEY, ocap.getStatus())) {
                List<Map> units = unitQueryManager.getUnitListByLot(ocap.getLotRrn());
                List<Map<String, Object>> ocapUnits = new ArrayList<>();
                for (Map map : units) {
                    ocapUnits.add(map);
                }
                ocapCardDTO.setUnits(ocapUnits);
            }
            return ocapCardDTO;
        }

        private void buildOcapStepOwner(OcapCardDTO ocapCardDTO) {
            List<OcapStepOwner> stepOwners = queryDAO.getOcapStepOwners(ocapCardDTO);
            ocapCardDTO.setStepOwners(stepOwners);

            StringJoiner sj = new StringJoiner(",");
            for (OcapStepOwner stepOwner : stepOwners) {
                sj.add(stepOwner.getStepOwnerId());
            }
            ocapCardDTO.setSignerId(sj.toString());
        }

        private OcapCardDTO buildOcapCardDTO(OcapCard ocap) {
            Assert.isFalse(ocap == null || ocap.getOcapRrn() == null || ocap.getOcapRrn() <= 0, Errors.create().content(
                    "Can't find the OCAP, please confirm that it already exists in the system.").build());
            OcapCardDTO ocapInformationDTO = new OcapCardDTO();
            BeanUtils.copyProperties(ocap, ocapInformationDTO);
            return ocapInformationDTO;
        }

        private OcapStepDTO buildOcapStep(OcapCardDTO ocapCardDTO) {
            // 根据执行RRN 获取当前step rrn
            if (Objects.isNull(ocapCardDTO.getExecutionRrn()) || ocapCardDTO.getExecutionRrn() <= 0L) {
                return null;
            }

            WorkflowInstance workflowInstance = workflowManagerService.getWorkflowInstance(ocapCardDTO.getExecutionRrn());
            WorkflowPath path = workflowInstance.getPath();
            WorkflowStepModel stepModel = workflowManagerService.getWorkflowStepModel(path.getCurrentStepRrn());

            OcapStepDTO stepDTO = new OcapStepDTO();
            stepDTO.setStepRrn(stepModel.getStepRrn());
            stepDTO.setStepId(stepModel.getStepId());
            stepDTO.setStatus(stepModel.getComments());

            // 根据step rrn 获取 link id
            List<Map<String, Object>> linkInfos = workflowManager.getWflPathsByCurNode(stepModel.getStepRrn());
            if (CollectionUtils.isNotEmpty(linkInfos)) {
                stepDTO.setActions(linkInfos.stream().map(map -> {
                    OcapStepActionDTO actionDTO = new OcapStepActionDTO();
                    actionDTO.setPathId(MapUtils.getString(map, "pathId"));
                    actionDTO.setActionId(
                            StringUtils.substringAfterLast(MapUtils.getString(map, "pathId"), StringUtils.UNDERLINE));
                    //设置按钮显示的优先级，越小越靠前
                    if (StringUtils.isNotEmptyTrim(actionDTO.getActionId())) {
                        actionDTO.setShowPriority(ActionIdEnum.valueOf(actionDTO.getActionId()).getSequence());
                    } else {
                        actionDTO.setShowPriority(0);
                    }
                    WorkflowStepModel nextStepModel = workflowManagerService.getWorkflowStepModel(
                            MapUtils.getLongValue(map, "nextStepRrn", 0));
                    actionDTO.setNextStepId(nextStepModel.getStepId());

                    return actionDTO;
                }).collect(Collectors.toList()));
            }
            stepDTO.getActions().sort(Comparator.comparingInt(OcapStepActionDTO::getShowPriority));
            return stepDTO;
        }

        private List<OcapTransDataDTO> buildTransDatas(Long ocapRrn) {
            List<OcapTransData> transDatas = getTransDatasByOcapRrn(ocapRrn);
            if (CollectionUtils.isEmpty(transDatas)) {
                return null;
            }
            return transDatas.stream().map(transData -> {
                OcapTransDataDTO transDataDTO = new OcapTransDataDTO();
                BeanUtils.copyProperties(transData, transDataDTO);
                return transDataDTO;
            }).collect(Collectors.toList());
        }

        private List<OcapTransLogDTO> buildTransLogs(Long ocapRrn) {
            List<OcapTransLog> transLogs = getTransLogsByOcapRrn(ocapRrn);
            if (CollectionUtils.isEmpty(transLogs)) {
                return null;
            }

            return transLogs.stream().map(transLog -> {
                OcapTransLogDTO transLogDTO = new OcapTransLogDTO();
                BeanUtils.copyProperties(transLog, transLogDTO);
                return transLogDTO;
            }).collect(Collectors.toList());
        }

        private OcapCardDTO getOcapInfoByLot(Long facilityRrn, Long lotRrn) {
            String ocapId = getActiveInlineOcapId(lotRrn);
            if (StringUtils.isEmpty(ocapId)) {
                return null;
            }
            Lot lot = lotQueryManager.getLot(lotRrn);
            return getOcapInfo(facilityRrn, ocapId, lot.getLotId());
        }

        private List<String> getActiveOfflineOcapIdsByProcessEquipment(Long equipmentRrn) {
            List<String> planIds = queryDAO.getOcapIdsByProcessEquipment(equipmentRrn, OcapTypeEnum.OFFLINE.toString(),
                                                                         VersionStatus.ACTIVE_KEY);
            if (CollectionUtils.isEmpty(planIds)) {
                planIds = Collections.emptyList();
            }
            return planIds;
        }

    }