ProductAttributeItemManagerImpl.java

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

import com.mycim.framework.jdbc.Page;
import com.mycim.framework.utils.beans.BeanUtils;
import com.mycim.framework.utils.lang.BooleanUtils;
import com.mycim.framework.utils.lang.collections.CollectionUtils;
import com.mycim.framework.utils.lang.time.DateUtils;
import com.mycim.server.base.manager.TransactionLogManager;
import com.mycim.server.prp.manager.ProductVersionManager;
import com.mycim.server.spec.dao.ProductAttributeItemDao;
import com.mycim.server.spec.dao.ProductAttributeItemHistoryDao;
import com.mycim.server.spec.manager.*;
import com.mycim.valueobject.bas.TransactionLog;
import com.mycim.valueobject.consts.VersionStatus;
import com.mycim.valueobject.prp.Ecn;
import com.mycim.valueobject.prp.ProcessSpecInfo;
import com.mycim.valueobject.prp.ProcessSpecItem;
import com.mycim.valueobject.prp.ProductAttributeFormDto;
import com.mycim.valueobject.prp.ProductAttributeHistoryQueryDto;
import com.mycim.valueobject.prp.ProductAttributeInfo;
import com.mycim.valueobject.prp.ProductAttributeItem;
import com.mycim.valueobject.prp.ProductSpecItem;
import com.mycim.valueobject.prp.ProductVariableEnum;
import com.mycim.valueobject.prp.ProductVersion;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.Override;
import java.util.*;

/**
 * Product Attribute
 *
 * @author Qiansheng.Wang
 * @since 2021-05-15
 */
@Service
@Transactional
public class ProductAttributeItemManagerImpl implements ProductAttributeItemManager {

    @Autowired
    ProductAttributeItemDao productAttributeItemDao;

    @Autowired
    ProductAttributeItemHistoryDao productAttributeItemHistoryDao;

    @Autowired
    TransactionLogManager transactionLogManager;

    @Autowired
    ProductVersionManager productVersionManager;

    @Autowired
    ProductSpecInfoManager productSpecInfoManager;

    @Autowired
    ProcessSpecItemManager processSpecItemManager;

    @Autowired
    ProcessSpecInfoManager processSpecInfoManager;

    @Autowired
    ActivationAttributeManager activationAttributeManager;

    @Autowired
    ProductAttributeInfoManager productAttributeInfoManager;

    @Override
    public void insertProductAttributeItems(TransactionLog transactionLog,
                                            List<ProductAttributeItem> productAttributeItems) {
        if (CollectionUtils.isEmpty(productAttributeItems)) {
            return;
        }

        for (ProductAttributeItem productAttributeItem : productAttributeItems) {
            productAttributeItem.setStatus(VersionStatus.UNFROZEN_KEY);

            productAttributeItem.setEcnRrn(null);
            productAttributeItem.setEffectiveTime(null);
            productAttributeItem.setTerminatedTime(null);

            productAttributeItem.setCreatedUser(transactionLog.getTransPerformedBy());
            productAttributeItem.setCreatedTime(transactionLog.getTransStartTimestamp());

            productAttributeItem.setUpdatedUser(transactionLog.getTransPerformedBy());
            productAttributeItem.setUpdatedTime(transactionLog.getTransStartTimestamp());
        }

        productAttributeItemDao.insertProductAttributeItems(productAttributeItems);
        productAttributeItemHistoryDao.insertProductAttributeItemHistories(transactionLog, productAttributeItems);
    }

    @Override
    public void deleteProductAttributeItems(TransactionLog transactionLog,
                                            List<ProductAttributeItem> productAttributeItems) {
        if (CollectionUtils.isEmpty(productAttributeItems)) {
            return;
        }
        productAttributeItemDao.deleteProductAttributeItems(productAttributeItems);
        productAttributeItemHistoryDao.insertProductAttributeItemHistories(transactionLog, productAttributeItems);
    }

    @Override
    public void updateProductAttributeItems(TransactionLog transactionLog,
                                            List<ProductAttributeItem> productAttributeItems) {
        if (CollectionUtils.isEmpty(productAttributeItems)) {
            return;
        }

        for (ProductAttributeItem productAttributeItem : productAttributeItems) {
            productAttributeItem.setUpdatedUser(transactionLog.getTransPerformedBy());
            productAttributeItem.setUpdatedTime(transactionLog.getTransStartTimestamp());
        }

        productAttributeItemDao.updateProductAttributeItems(productAttributeItems);
        productAttributeItemHistoryDao.insertProductAttributeItemHistories(transactionLog, productAttributeItems);
    }

    @Override
    public void updateStatusOfProductAttributeItems(TransactionLog transactionLog,
                                                    List<ProductAttributeItem> productAttributeItems, Ecn ecn,
                                                    String targetStatus) {
        for (ProductAttributeItem attributeItem : productAttributeItems) {

            attributeItem.setStatus(targetStatus);
            attributeItem.setUpdatedTime(transactionLog.getTransStartTimestamp());
            attributeItem.setUpdatedUser(transactionLog.getTransPerformedBy());

            if (ecn != null) {
                attributeItem.setEcnRrn(ecn.getInstanceRrn());
                attributeItem.setEffectiveTime(DateUtils.stringToTimestamp(ecn.getEffectiveDateFrom()));
                attributeItem.setTerminatedTime(DateUtils.stringToTimestamp(ecn.getEffectiveDateTo()));
            }

        }

        productAttributeItemDao.updateStatusOfProductAttributeItems(productAttributeItems);
        productAttributeItemHistoryDao.insertProductAttributeItemHistories(transactionLog, productAttributeItems);
    }

    @Override
    public void saveProductAttribute(TransactionLog transactionLog, ProcessSpecInfo processSpecInfo,
                                     List<ProcessSpecItem> processSpecItems, List<ProductVersion> allProductVersions) {
        saveProductAttribute(transactionLog, processSpecInfo, processSpecItems, allProductVersions, false);
    }

    @Override
    public void saveProductAttributeWithReset(TransactionLog transactionLog, ProcessSpecInfo processSpecInfo,
                                              List<ProcessSpecItem> processSpecItems,
                                              List<ProductVersion> allProductVersions) {
        saveProductAttribute(transactionLog, processSpecInfo, processSpecItems, allProductVersions, true);
    }

    private void saveProductAttribute(TransactionLog transactionLog, ProcessSpecInfo processSpecInfo,
                                      List<ProcessSpecItem> processSpecItems, List<ProductVersion> allProductVersions,
                                      boolean needReset) {
        // Build product attribute item templates
        List<ProductAttributeItem> productAttributeItemTemplates = buildProductAttributeItemTemplates(processSpecItems);

        // Build product attribute table infos
        List<ProductAttributeInfo> willSaveProductAttributeInfos = buildProductAttributeInfos(processSpecInfo,
                                                                                              allProductVersions);

        // Get the highest active version of the spec item
        Integer highestActivatedProcessVersion = processSpecInfoManager
                .getHighestActivatedProcessVersion(processSpecInfo.getProcessRrn());
        List<ProductSpecItem> highestActivatedProductSpecItems = activationAttributeManager
                .getActiveProductSpec(processSpecInfo.getProcessRrn(), highestActivatedProcessVersion);

        List<ProductAttributeItem> willSaveProductAttributeItems = new ArrayList<>();

        List<ProductAttributeItem> productAttributeItemsInDb = getProductAttributeItems(processSpecInfo.getProcessRrn(),
                                                                                        processSpecInfo
                                                                                                .getProcessVersion());
        // Build current product spec item and copy from the highest active version of the spec item
        for (ProductAttributeInfo productAttributeInfo : willSaveProductAttributeInfos) {
            willSaveProductAttributeItems
                    .addAll(buildProductAttributeItems(productAttributeItemTemplates, productAttributeInfo,
                                                       highestActivatedProcessVersion,
                                                       highestActivatedProductSpecItems));
        }

        if (CollectionUtils.isNotEmpty(willSaveProductAttributeInfos) &&
                (CollectionUtils.isNotEmpty(willSaveProductAttributeItems) ||
                        CollectionUtils.isNotEmpty(productAttributeItemsInDb))) {
            productAttributeInfoManager
                    .saveProductAttributeInfos(transactionLog, processSpecInfo, willSaveProductAttributeInfos);

            saveProductAttributeItems(transactionLog, processSpecInfo, willSaveProductAttributeItems, needReset);

            //若535修改删除了所有变量则表示当前flow为全常量,将PROD_ATTRIBUTE_INFO表中对应数据删除
            List<ProductAttributeItem> productAttributeItems = getProductAttributeItems(processSpecInfo.getProcessRrn(),
                                                                                        processSpecInfo
                                                                                                .getProcessVersion());
            if (CollectionUtils.isEmpty(productAttributeItems)) {
                 productAttributeInfoManager.deleteProductAttributeInfos(willSaveProductAttributeInfos);
            }
        }
    }

    private void saveProductAttributeItems(TransactionLog transactionLog, ProcessSpecInfo processSpecInfo,
                                           List<ProductAttributeItem> willSaveProductAttributeItems,
                                           boolean needReset) {
        Map<String, List<ProductAttributeItem>> productAttributeItemSaveMap = new HashMap<>();

        productAttributeItemSaveMap.put("insertItems", new ArrayList<>());
        productAttributeItemSaveMap.put("updateItems", new ArrayList<>());
        productAttributeItemSaveMap.put("deleteItems", new ArrayList<>());

        List<ProductAttributeItem> productAttributeItemsInDb = getProductAttributeItems(processSpecInfo.getProcessRrn(),
                                                                                        processSpecInfo
                                                                                                .getProcessVersion());

        for (ProductAttributeItem item : willSaveProductAttributeItems) {
            if (!productAttributeItemsInDb.contains(item)) {
                // insert
                productAttributeItemSaveMap.get("insertItems").add(item);
            } else {
                //update
                productAttributeItemSaveMap.get("updateItems").add(item);
            }
        }

        if (needReset) {
            for (ProductAttributeItem item : productAttributeItemsInDb) {
                if (!willSaveProductAttributeItems.contains(item)) {
                    // delete
                    productAttributeItemSaveMap.get("deleteItems").add(item);
                }
            }
        }


        List<ProductAttributeItem> insertItems = productAttributeItemSaveMap.get("insertItems");
        List<ProductAttributeItem> deleteItems = productAttributeItemSaveMap.get("deleteItems");
        insertProductAttributeItems(transactionLog, insertItems);
        deleteProductAttributeItems(transactionLog, deleteItems);
        if (CollectionUtils.isNotEmpty(insertItems) || CollectionUtils.isNotEmpty(deleteItems)) {
            updateStatusOfProductAttributeItems(transactionLog, productAttributeItemSaveMap.get("updateItems"), null,
                                                VersionStatus.UNFROZEN_KEY);
        }
    }

    private List<ProductAttributeItem> buildProductAttributeItems(
            List<ProductAttributeItem> productAttributeItemTemplates, ProductAttributeInfo productAttributeInfo,
            Integer latestActivatedProcessVersion, List<ProductSpecItem> latestActivatedProductSpecItems) {

        List<ProductAttributeItem> result = new ArrayList<>();
        for (ProductAttributeItem template : productAttributeItemTemplates) {
            ProductAttributeItem attribute = new ProductAttributeItem();

            BeanUtils.copyProperties(template, attribute);

            attribute.setProductRrn(productAttributeInfo.getProductRrn());
            attribute.setProductId(productAttributeInfo.getProductId());
            attribute.setProductVersion(productAttributeInfo.getProductVersion());

            ProductSpecItem productSpecItemTemp = new ProductSpecItem();

            BeanUtils.copyProperties(attribute, productSpecItemTemp);

            productSpecItemTemp.setProcessVersion(latestActivatedProcessVersion);

            int index = latestActivatedProductSpecItems.indexOf(productSpecItemTemp);

            if (index >= 0) {
                productSpecItemTemp = latestActivatedProductSpecItems.get(index);

                if (ProductVariableEnum.isRecipeVariable(attribute.getAttributeName())) {
                    attribute.setAttributeValue(productSpecItemTemp.getRecipeId());
                    attribute.setAttributeValueRrn(productSpecItemTemp.getRecipeRrn());
                }
                if (ProductVariableEnum.isReticleGroupVariable(attribute.getAttributeName())) {
                    attribute.setAttributeValue(productSpecItemTemp.getReticleFamilyId());
                    attribute.setAttributeValueRrn(productSpecItemTemp.getReticleFamilyRrn());
                }
                if (ProductVariableEnum.isEdcPlanVariable(attribute.getAttributeName())) {
                    attribute.setAttributeValue(productSpecItemTemp.getParameterSetId());
                    attribute.setAttributeValueRrn(productSpecItemTemp.getParameterSetRrn());
                }
            }

            result.add(attribute);
        }

        return result;
    }

    private List<ProductAttributeInfo> buildProductAttributeInfos(ProcessSpecInfo processSpecInfo,
                                                                  List<ProductVersion> allProductVersions) {
        List<ProductAttributeInfo> willSaveProductAttributeInfos = new ArrayList<>();

        for (ProductVersion productVersion : allProductVersions) {
            ProductAttributeInfo info = new ProductAttributeInfo();

            info.setProductRrn(productVersion.getProductRrn());
            info.setProductId(productVersion.getProductId());
            info.setProductVersion(productVersion.getInstanceVersion());
            info.setProcessId(processSpecInfo.getProcessId());
            info.setProcessRrn(processSpecInfo.getProcessRrn());
            info.setProcessVersion(processSpecInfo.getProcessVersion());

            willSaveProductAttributeInfos.add(info);
        }
        return willSaveProductAttributeInfos;
    }

    /**
     * Build the {@code ProductAttributeDetailInfo} template to be added.
     *
     * @param processSpecItems saved process spec item list
     * @return List of templates constructed according to processSpecItems
     */
    private List<ProductAttributeItem> buildProductAttributeItemTemplates(List<ProcessSpecItem> processSpecItems) {
        List<ProductAttributeItem> productAttributeItems = new ArrayList<>();

        for (ProcessSpecItem processSpecItem : processSpecItems) {
            if (!BooleanUtils.toBoolean(processSpecItem.getVariableFlag())) {
                continue;
            }

            addProductAttributeItems(productAttributeItems, processSpecItem, processSpecItem.getRecipeRrn(),
                                     processSpecItem.getRecipeId());

            addProductAttributeItems(productAttributeItems, processSpecItem, processSpecItem.getReticleFamilyRrn(),
                                     processSpecItem.getReticleFamilyId());

            addProductAttributeItems(productAttributeItems, processSpecItem, processSpecItem.getParameterSetRrn(),
                                     processSpecItem.getParameterSetId());
        }
        return productAttributeItems;
    }

    /**
     * Add the {@code ProductAttributeDetailInfo} to {@code productAttributeItems}
     *
     * @param productAttributeItems Target list
     * @param processSpecItem       Template data
     * @param attributeNameRrn      Instance RRN (like. Recipe RRN, Parameter Set RRN, Reticle Family RRN)
     * @param attributeName         Instance ID (like. Recipe ID, Parameter Set ID, Reticle Family ID)
     */
    private void addProductAttributeItems(List<ProductAttributeItem> productAttributeItems,
                                          ProcessSpecItem processSpecItem, Long attributeNameRrn,
                                          String attributeName) {
        if (attributeNameRrn != null && attributeNameRrn > 0 && ProductVariableEnum.isVariable(attributeName)) {
            ProductAttributeItem productAttributeItem = new ProductAttributeItem();

            BeanUtils.copyProperties(processSpecItem, productAttributeItem);

            productAttributeItem.setAttributeNameRrn(attributeNameRrn);
            productAttributeItem.setAttributeName(attributeName);

            productAttributeItems.add(productAttributeItem);
        }
    }

    @Override
    public List<ProductAttributeItem> getProductAttributeItems(Long processRrn, Integer processVersion) {
        ProductAttributeItem attributeItemQueryTemp = new ProductAttributeItem();
        attributeItemQueryTemp.setProcessRrn(processRrn);
        attributeItemQueryTemp.setProcessVersion(processVersion);
        return getProductAttributeItems(attributeItemQueryTemp);
    }

    @Override
    public List<ProductAttributeItem> getProductAttributeItems(Long processRrn, Integer processVersion, Long productRrn,
                                                               Integer productVersion) {
        ProductAttributeItem attributeItemQueryTemp = new ProductAttributeItem();
        attributeItemQueryTemp.setProductRrn(productRrn);
        attributeItemQueryTemp.setProductVersion(productVersion);
        attributeItemQueryTemp.setProcessRrn(processRrn);
        attributeItemQueryTemp.setProcessVersion(processVersion);
        return getProductAttributeItems(attributeItemQueryTemp);
    }

    private List<ProductAttributeItem> getProductAttributeItems(ProductAttributeItem attributeItemQueryTemp) {
        List<ProductAttributeItem> items = productAttributeItemDao
                .getProductAttributeItemsWithPrimaryKey(attributeItemQueryTemp);
        if (items == null) {
            items = new ArrayList<>();
        }
        return items;
    }

    @Override
    public List<ProductAttributeItem> queryProductAttributeItems(ProductAttributeFormDto queryInfo) {
        List<ProductAttributeItem> result = productAttributeItemDao.queryProductAttributeItems(queryInfo);
        if (CollectionUtils.isEmpty(result)) {
            result = Collections.emptyList();
        }
        return result;
    }

    @Override
    public Page queryProductAttributeHistories(ProductAttributeHistoryQueryDto historyQuery) {
        Page page = new Page(historyQuery.getPageNo(), historyQuery.getPageSize());

        return productAttributeItemHistoryDao.queryProductAttributeHistories(page, historyQuery);
    }

}