ProductAttributeAction.java

package com.mycim.webapp.actions.spec;

import com.fa.sesa.exception.Assert;
import com.fa.sesa.exception.Errors;
import com.fa.sesa.exception.SystemIllegalArgumentException;
import com.fa.sesa.i18n.I18nUtils;
import com.fa.sesa.threadlocal.LocalContext;
import com.mycim.framework.file.excel.im.ExcelImport;
import com.mycim.framework.file.excel.im.ExcelParser;
import com.mycim.framework.file.excel.im.ExcelRow;
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.valueobject.MessageIdList;
import com.mycim.valueobject.ObjectList;
import com.mycim.valueobject.Pair;
import com.mycim.valueobject.consts.VersionStatus;
import com.mycim.valueobject.prp.*;
import com.mycim.webapp.TemplateLocation;
import com.mycim.webapp.WebUtils;
import com.mycim.webapp.actions.PrpSetupAction;
import com.mycim.webapp.forms.RecipeContextValueForm;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.upload.FormFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.Override;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Product Attribute Table
 *
 * @author Qiansheng.Wang
 * @since 2021-05-15
 */
public class ProductAttributeAction extends PrpSetupAction {

    @Override
    public ActionForward init(ActionMapping mapping, ActionForm form, HttpServletRequest request,
                              HttpServletResponse response) throws Exception {
        return mapping.getInputForward();
    }

    public Map<String, Object> query(ProductAttributeFormDto productAttributeForm) {
        List<ProductAttributeItemDto> productAttributeItems = productAttributeService
                .queryProductAttributeItems(buildForm(productAttributeForm));

        Map<String, Object> result = new HashMap<>();

        result.put("totalItems", productAttributeItems.size());
        result.put("items", productAttributeItems);
        result.put("productVersionItemsMap", buildProductVersionComboboxItems(productAttributeForm.getProductRrns()));
        return result;
    }

    public void saveProductAttribute(ProductAttributeFormDto productAttributeForm) {
        productAttributeService.saveProductAttributeDetailInfo(buildForm(productAttributeForm));
    }

    public void freezeProductAttribute(ProductAttributeFormDto productAttributeForm) {
        productAttributeService.freezeProductAttributeDetailInfo(buildForm(productAttributeForm));
    }

    public void unfreezeProductAttribute(ProductAttributeFormDto productAttributeForm) {
        productAttributeService.unfreezeProductAttributeDetailInfo(buildForm(productAttributeForm));
    }

    public void activateProductAttribute(ProductAttributeFormDto productAttributeForm) {
        productAttributeService.activateProductAttributeDetailInfo(buildForm(productAttributeForm));
    }

    public void addProductVersion(ProductAttributeFormDto productAttributeForm) {
        buildForm(productAttributeForm);

        Assert.isFalse(CollectionUtils.isEmpty(productAttributeForm.getProductRrns()),
                       Errors.create().content("Not product is related to current process!").build());

        productAttributeService.addProductVersion(productAttributeForm);
    }

    @SuppressWarnings("unchecked")
    public ActionForward exportProductAttribute(HttpServletRequest request,
                                                HttpServletResponse response) throws Exception {
        Map<String, Object> map = WebUtils.getExportParams(request);

        ProductAttributeFormDto productAttributeForm = new ProductAttributeFormDto();

        productAttributeForm.setProcessId(MapUtils.getString(map, "processId"));
        productAttributeForm.setProcessVersion(MapUtils.getInteger(map, "processVersion"));
        productAttributeForm.setFlowSeqs(((List<String>) map.get("flowSeqs")).stream().filter(StringUtils::isNotBlank)
                                                                             .collect(Collectors.toList()));
        productAttributeForm.setProductRrns(
                ((List<String>) map.get("productRrns")).stream().filter(StringUtils::isNotBlank)
                                                       .map(NumberUtils::toLong).collect(Collectors.toList()));
        productAttributeForm.setProductVersions(
                ((List<String>) map.get("productVersions")).stream().filter(StringUtils::isNotBlank)
                                                           .map(NumberUtils::toInt).collect(Collectors.toList()));
        productAttributeForm.setAttributeNameRrns(
                ((List<String>) map.get("attributeNameRrns")).stream().filter(StringUtils::isNotBlank)
                                                             .map(NumberUtils::toLong).collect(Collectors.toList()));

        List<ProductAttributeItemDto> productAttributeItems = productAttributeService
                .queryProductAttributeItems(buildForm(productAttributeForm));

        List<Map<String, Object>> list = new ArrayList<>();
        for (int i = 0; i < productAttributeItems.size(); i++) {
            ProductAttributeItemDto productAttributeItem = productAttributeItems.get(i);

            Map<String, Object> item = BeanUtils.copyBeanToMap(productAttributeItem);
            item.put("seq", i + 1);
            list.add(item);
        }

        Map<String, Object> titles = WebUtils.getExportTitles(request);
        if (StringUtils.equalsIgnoreCase("CN", I18nUtils.getCurrentLanguage().toString())) {
            titles.put("seq", "序号");
            titles.put("productAttributeInfo", "产品属性信息");
            titles.put("processId", "流程号:" + productAttributeForm.getProcessId());
            titles.put("processVer", "流程版本号:" + productAttributeForm.getProcessVersion());
        } else {
            titles.put("seq", "seq");
            titles.put("productAttributeInfo", "Product Attribute Info");
            titles.put("processId", "Process Id:" + productAttributeForm.getProcessId());
            titles.put("processVer", "Process Version:" + productAttributeForm.getProcessVersion());
        }

        String fileName = "ProductAttributeList_" + DateUtils.getNowTime(DateUtils.DATE_FORMAT4NOSPLICING) + ".xlsx";

        WebUtils.exportExcel(fileName, titles, list, TemplateLocation.PRODUCT_ATTRIBUTE, response);
        return WebUtils.NULLActionForward;
    }

    public Map<String, Object> importFromExcel(RecipeContextValueForm theForm) {
        FormFile upFile = theForm.getUpFile();
        String fileName = upFile.getFileName();

        Assert.isFalse(StringUtils.isEmpty(fileName), Errors.create().key(MessageIdList.SPEC_PLEASE_SELECT_EXCEL)
                                                            .content("Please select the Excel file to import!")
                                                            .build());

        return productAttributeService.checkImportProductSpecItems(buildImportData(upFile));
    }

    private List<ProductAttributeItemDto> buildImportData(FormFile upFile) {
        try {
            ExcelImport excelImport = new ExcelImport().tableFrom(6);
            return excelImport.mapper(new ExcelParser<Object, ProductAttributeItemDto>() {

                @Override
                public Object attributeMapper(List<ExcelRow> attributeRows, int attributeFrom, int attributeTo) {
                    return null;
                }

                @Override
                public ProductAttributeItemDto tableRowMapper(ExcelRow excelRow, int rowNum, Object attributeData) {
                    if (rowNum == 6) {
                        return null;
                    }
                    ProductAttributeItemDto productAttributeItem = new ProductAttributeItemDto();

                    productAttributeItem.setProductId(StringUtils.trimToUpperCase(excelRow.getString(1)));
                    productAttributeItem.setProductVersion((int) NumberUtils.toDouble(excelRow.getString(2)));
                    productAttributeItem.setProcessVersion((int) NumberUtils.toDouble(excelRow.getString(3)));
                    productAttributeItem.setFlowSeq(StringUtils.trim(excelRow.getString(4)));
                    productAttributeItem.setAttributeName(StringUtils.trimToUpperCase(excelRow.getString(5)));
                    productAttributeItem.setAttributeValue(StringUtils.trimToUpperCase(excelRow.getString(6)));

                    return productAttributeItem;
                }
            }).file(upFile.getInputStream()).getTableDataList();
        } catch (Exception e) {
            throw new SystemIllegalArgumentException(Errors.create().key(MessageIdList.SYSTEM_UPLOAD_FILE_FAILURE)
                                                           .content("Failed to parse the file. Please check if " +
                                                                            "the file matches!").build());
        }
    }

    public Map<String, Object> queryComboboxItemsByProcess(Map<String, Object> map) {
        String processId = StringUtils.trimToUpperCase(MapUtils.getString(map, "processId"));

        ProcessPlanning processPlanning = new ProcessPlanning(
                processId, getNamedSpace(ObjectList.WFL_KEY, LocalContext.getFacilityRrn()), ObjectList.WFL_KEY);
        processPlanning = prpService.getProcessPlanning(processPlanning);
        long processRrn = processPlanning != null ? processPlanning.getInstanceRrn():0;
        if (processRrn <= 0) {
            return Collections.emptyMap();
        }

        List<Pair<Long, String>> productComboboxItems = buildProductComboboxItems(processRrn);

        List<Long> productRrns = new ArrayList<>();
        for (Pair<Long, String> comboboxItem : productComboboxItems) {
            productRrns.add(comboboxItem.getKey());
        }

        Map<String, Object> queryConditions = new HashMap<>();

        queryConditions.put("processVersionItems", buildProcessVersionComboboxItems(processRrn));
        queryConditions.put("productIdItems", productComboboxItems);
        queryConditions.put("productVersionItemsMap", buildProductVersionComboboxItems(productRrns));

        return queryConditions;
    }

    private List<Pair<Integer, Object>> buildProcessVersionComboboxItems(Long processRrn) {
        List<Pair<Integer, Object>> result = new ArrayList<>();

        ProcessPlanning processPlanning = new ProcessPlanning();
        processPlanning.setInstanceRrn(processRrn);
        List<ProcessVersion> processVersions = prpService.getProcessVersions(processPlanning);

        for (ProcessVersion processVersion : processVersions) {
            int version = processVersion.getInstanceVersion();
            String versionDesc = version + " (" + processVersion.getVersionStatus() + ")";

            result.add(new Pair<>(version, versionDesc));
        }

        return result;
    }

    private List<Pair<Long, String>> buildProductComboboxItems(Long processRrn) {
        List<Pair<Long, String>> result = new ArrayList<>();

        for (Item item : prpService.getUsedByProducts(processRrn)) {
            result.add(new Pair<>(item.getInstanceRrn(), item.getInstanceId()));
        }

        return result;
    }

    private Map<Long, List<Pair<Integer, String>>> buildProductVersionComboboxItems(List<Long> productRrns) {
        Map<Long, List<Pair<Integer, String>>> result = new HashMap<>();

        for (Long productRrn : productRrns) {

            List<Pair<Integer, String>> productVersionComboboxItems = new ArrayList<>();

            result.put(productRrn, productVersionComboboxItems);

            List<ProductVersion> productVersions = productService.getProductVersions(productRrn);
            for (ProductVersion productVersion : productVersions) {
                int instanceVersion = productVersion.getInstanceVersion();
                String instanceVersionDesc = instanceVersion + " (" + productVersion.getVersionStatus() + ")";

                Pair<Integer, String> comboboxItem = new Pair<>(instanceVersion, instanceVersionDesc);
                if (!productVersionComboboxItems.contains(comboboxItem)) {
                    productVersionComboboxItems.add(comboboxItem);
                }
            }
        }
        return result;
    }

    public Map<String, Object> queryComboboxItemsForTableInfo(Map<String, Object> map) {
        Long facilityRrn = LocalContext.getFacilityRrn();
        String processId = MapUtils.getString(map, "processId");
        Integer processVersion = MapUtils.getInteger(map, "processVersion");

        long processRrn = this.getInstanceRrn(processId, facilityRrn, ObjectList.WFL_KEY);

        if (processRrn <= 0 || processVersion == null || processVersion <= 0) {
            return Collections.emptyMap();
        }

        List<Pair<Long, String>> attributeNameComboboxItems = new ArrayList<>();
        List<Pair<String, String>> flowSeqComboboxItems = new ArrayList<>();

        ProductAttributeFormDto productAttributeForm = new ProductAttributeFormDto();

        productAttributeForm.setProcessRrn(processRrn);
        productAttributeForm.setProcessVersion(processVersion);

        List<ProductAttributeItemDto> variables = productAttributeService
                .queryProductAttributeItems(productAttributeForm);

        for (ProductAttributeItemDto variable : variables) {
            Pair<String, String> flowSeqPair = new Pair<>(variable.getFlowSeq(), variable.getFlowSeq());

            if (!flowSeqComboboxItems.contains(flowSeqPair)) {
                flowSeqComboboxItems.add(flowSeqPair);
            }

            Pair<Long, String> attributeNamePair = new Pair<>(variable.getAttributeNameRrn(),
                                                              variable.getAttributeName());

            if (!attributeNameComboboxItems.contains(attributeNamePair)) {
                attributeNameComboboxItems.add(attributeNamePair);
            }
        }

        flowSeqComboboxItems.sort(Comparator.comparing(Pair::getKey));
        attributeNameComboboxItems.sort(Comparator.comparing(Pair::getValue));

        Map<String, Object> queryConditions = new HashMap<>();

        queryConditions.put("attributeNameItems", attributeNameComboboxItems);
        queryConditions.put("flowSeqItems", flowSeqComboboxItems);

        return queryConditions;
    }

    private ProductAttributeFormDto buildForm(ProductAttributeFormDto productAttributeForm) {
        productAttributeForm.setProcessId(StringUtils.trimToUpperCase(productAttributeForm.getProcessId()));

        String processId = productAttributeForm.getProcessId();
        Integer processVersion = productAttributeForm.getProcessVersion();

        Assert.isFalse(StringUtils.isEmpty(processId), Errors.create().content("Process ID can not be empty!").build());

        Assert.isFalse(processVersion == null || processVersion <= 0,
                       Errors.create().content("Invalid process version!").build());

        long processRrn = this.getInstanceRrn(processId, LocalContext.getFacilityRrn(), ObjectList.WFL_KEY);

        Assert.isFalse(processRrn <= 0, Errors.create().content("Process does not exist!").build());

        ProcessVersion version = prpService.getProcessVersion(processRrn, processVersion);

        Assert.isFalse(VersionStatus.UNFROZEN_KEY.equals(version.getVersionStatus()),
                       Errors.create().content("Please freeze the process!").build());

        productAttributeForm.setProcessRrn(processRrn);
        productAttributeForm.setProcessVersion(processVersion);

        if (CollectionUtils.isNotEmpty(productAttributeForm.getFlowSeqs())) {
            productAttributeForm.setFlowSeqs(productAttributeForm.getFlowSeqs().stream().filter(StringUtils::isNotEmpty)
                                                                 .collect(Collectors.toList()));
        }

        if (CollectionUtils.isNotEmpty(productAttributeForm.getProductRrns())) {
            productAttributeForm.setProductIds(new ArrayList<>());

            productAttributeForm.setProductRrns(productAttributeForm.getProductRrns().stream().filter(Objects::nonNull)
                                                                    .collect(Collectors.toList()));

            productAttributeForm.getProductRrns().forEach(
                    productRrn -> productAttributeForm.getProductIds().add(StringUtils.toString(productRrn)));
        }

        if (CollectionUtils.isNotEmpty(productAttributeForm.getAttributeNameRrns())) {
            productAttributeForm.setAttributeNames(new ArrayList<>());

            productAttributeForm.setAttributeNameRrns(
                    productAttributeForm.getAttributeNameRrns().stream().filter(Objects::nonNull)
                                        .collect(Collectors.toList()));

            productAttributeForm.getAttributeNameRrns().forEach(
                    attributeNameRrn -> productAttributeForm.getAttributeNames()
                                                            .add(StringUtils.toString(attributeNameRrn)));
        }

        if (CollectionUtils.isNotEmpty(productAttributeForm.getProductVersions())) {
            productAttributeForm.setProductVersions(
                    productAttributeForm.getProductVersions().stream().filter(Objects::nonNull)
                                        .collect(Collectors.toList()));
        }

        return productAttributeForm;
    }

}