/**
 * 文件：MateriaBomServiceImpl.java
 * 版本：1.0.0
 * 日期：
 * Copyright &reg;
 * All right reserved.
 */

package com.mortals.xhx.module.materia.service.impl;

import com.alibaba.fastjson.JSON;
import com.mortals.framework.common.code.YesNo;
import com.mortals.framework.exception.AppException;
import com.mortals.framework.model.Context;
import com.mortals.framework.service.impl.AbstractCRUDServiceImpl;
import com.mortals.framework.util.DateUtils;
import com.mortals.framework.util.StringUtils;
import com.mortals.xhx.base.system.param.service.ParamService;
import com.mortals.xhx.common.code.BomStatusEnum;
import com.mortals.xhx.common.excel.core.ExcelUtils;
import com.mortals.xhx.common.excel.core.IExcelUtil;
import com.mortals.xhx.common.key.Constant;
import com.mortals.xhx.common.utils.BeanUtil;
import com.mortals.xhx.module.config.model.ConfigFieldQuery;
import com.mortals.xhx.module.config.service.ConfigFieldService;
import com.mortals.xhx.module.materia.dao.MateriaBomDao;
import com.mortals.xhx.module.materia.model.*;
import com.mortals.xhx.module.materia.service.*;
import com.mortals.xhx.module.supplier.model.SupplierEntity;
import com.mortals.xhx.module.supplier.model.SupplierQuery;
import com.mortals.xhx.module.supplier.service.SupplierService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>Title: BOM单表</p>
 * <p>Description: MateriaBomServiceImpl service接口 </p>
 * <p>Copyright: Copyright &reg;  </p>
 * <p>Company: </p>
 *
 * @author
 * @version 1.0.0
 */
@Service("materiaBomService")
public class MateriaBomServiceImpl extends AbstractCRUDServiceImpl<MateriaBomDao, MateriaBomEntity, Long> implements MateriaBomService {

    @Autowired
    private MateriaService materiaService;
    @Autowired
    private MateriaSupplierService materiaSupplierService;
    @Autowired
    private SupplierService supplierService;
    @Autowired
    private MateriaBomTreeService materiaBomTreeService;
    @Autowired
    private MateriaBomItemService materiaBomItemService;
    @Autowired
    private ConfigFieldService configFieldService;
    @Autowired
    private ParamService paramService;
    @Value("${upload.path}")
    private String filePath;
    @Autowired
    private MateriaCategoryService materiaCategoryService;


    @Override
    protected void saveBefore(MateriaBomEntity entity, Context context) throws AppException {
        MateriaBomTreeEntity bomTree = materiaBomTreeService.get(entity.getBomTreeId(), true);
        int count = getBomCountByTree(context, entity);
        //code自动生成
        entity.setCode(bomTree.getCode());
        entity.setSelfCode(count + "");
        entity.setBomTreeCode(bomTree.getCode());
        entity.setStatus(entity.getStatus() == null ? BomStatusEnum.BOM_EDIT.getValue() : entity.getStatus());

        entity.setCreateTime(new Date());
        entity.setCreateUser(context.getUser().getRealName());
        entity.setUpdateUser(context.getUser().getRealName());
        entity.setUpdateTime(new Date());

        //根据物料关联的多个bom中查询是否存在有待编辑或者审核中的bom
        MateriaBomQuery materiaBomQuery = new MateriaBomQuery();
        materiaBomQuery.setMateriaId(entity.getMateriaId());
        materiaBomQuery.setStatusList(Arrays.asList(BomStatusEnum.BOM_EDIT.getValue(), BomStatusEnum.BOM_AUDIT.getValue()));

        // materiaBomQuery.setUseType(entity.getUseType());
        MateriaBomEntity materiaBomEntity = this.find(materiaBomQuery, context).stream()
                .findAny().orElseGet(() -> null);
        if (!ObjectUtils.isEmpty(materiaBomEntity)) {
            throw new AppException(String.format("当前物料代码:%s,已存在相同的bom正在审核中或待编辑，不允许再次创建！", entity.getMateriaCode()));
        }


        MateriaEntity materiaEntity = materiaService.get(entity.getMateriaId(), context);
        if (!ObjectUtils.isEmpty(materiaEntity)) {
            entity.setMateriaName(materiaEntity.getName());
            entity.setMateriaCode(materiaEntity.getCode());
        }
    }


    @Override
    protected void saveAfter(MateriaBomEntity entity, Context context) throws AppException {
//        MateriaBomTreeEntity treeEntity = new MateriaBomTreeEntity();
//        treeEntity.initAttrValue();
//        treeEntity.setBomId(entity.getId());
//        treeEntity.setCode(entity.getMateriaCode());
//        treeEntity.setName(entity.getMateriaName());
//        treeEntity.setParentId(entity.getBomTreeId());
//        treeEntity.setIsLeaf(YesNo.YES.getValue());
//        treeEntity.setCreateTime(new Date());
//        treeEntity.setCreateUser(context.getUser().getRealName());
//        materiaBomTreeService.save(treeEntity,context);
//
        //判断父类非叶子节点
        MateriaBomTreeEntity materiaBomTreeEntity = materiaBomTreeService.get(entity.getBomTreeId(), context);
        if (!ObjectUtils.isEmpty(materiaBomTreeEntity)) {
            materiaBomTreeEntity.setIsLeaf(YesNo.NO.getValue());
            materiaBomTreeService.update(materiaBomTreeEntity, context);
        }

        //判断是否有bom-item引用此物品的物料bom
//        MateriaBomItemQuery materiaBomItemQuery = new MateriaBomItemQuery();
//        materiaBomItemQuery.setMateriaId(entity.getMateriaId());
//        materiaBomItemService.find(materiaBomItemQuery,context).stream().peek(item->{
//            item.setMateriaBomId(entity.getId());
//            materiaBomItemService.updateItem(item);
//        }).count();

    }


    @Override
    public String doImportBom(String materiaBomStr, Context context) {

        StringBuilder returnStr = new StringBuilder();
        int suc = 0;
        int fail = 0;
        returnStr.append("<div style=\"height:500px;overflow:scroll\">");

        // Map<String, String> bomUseTypeMap = paramService.getParamByFirstOrganize("BomUseType");
        Map<String, String> matriaSupplyType = paramService.getParamByFirstOrganize("MatriaSupplyType");
        MateriaImportBomEntity importBomEntity = JSON.parseObject(materiaBomStr, MateriaImportBomEntity.class);

        MateriaBomCustomEntity bom = importBomEntity.getBom();
//        String keyByLoop = getKeyByLoop(bomUseTypeMap, bom.getUseTypeName());
//        if (!ObjectUtils.isEmpty(keyByLoop)) {
//            bom.setUseType(Integer.parseInt(keyByLoop));
//        }

        List<MateriaBomItemCustomEntity> bomitems = importBomEntity.getBomitems();
        //查询当前产品树下，bomself是否已经存在 如果存在则不添加

        if (ObjectUtils.isEmpty(bom.getBomTreeId())) {
            throw new AppException("请选择BOM目录后导入！");
        }

        MateriaBomTreeEntity materiaBomTreeEntity = materiaBomTreeService.get(bom.getBomTreeId(), context);
        if (ObjectUtils.isEmpty(materiaBomTreeEntity)) {
            throw new AppException("bom表单未获取到bomTreeCode:" + bom.getBomTreeCode());
        }


        for (MateriaBomItemCustomEntity bomItemEntity : bomitems) {
            bomItemEntity.setBomId(bom.getId());
            //是否必选料
            bomItemEntity.setRequired(bomItemEntity.getRequiredName() == YesNo.YES.getDesc() ? YesNo.YES.getValue() : YesNo.NO.getValue());

            MateriaEntity materiaEntity = null;
            MateriaQuery materiaQuery = new MateriaQuery();
            if (!ObjectUtils.isEmpty(bomItemEntity.getMateriaCode())) {
                materiaQuery.setCode(bomItemEntity.getMateriaCode());
                materiaEntity = materiaService.find(materiaQuery, context).stream().findAny().orElseGet(() -> null);
                if (ObjectUtils.isEmpty(materiaEntity)) {
                    returnStr.append("当前行号：" + bomItemEntity.getRowNum());
                    returnStr.append(String.format(" 物料编码不存在:%s", bomItemEntity.getMateriaCode()));
                    returnStr.append("<br />");
                    fail++;
                    continue;
                }
            } else if (!ObjectUtils.isEmpty(bomItemEntity.getMateriaName())) {
                //通过物料name查询物料
                materiaQuery.setName(bomItemEntity.getMateriaName());
                if (!ObjectUtils.isEmpty(bomItemEntity.getCategoryCode())){
                    MateriaCategoryQuery categoryQuery = new MateriaCategoryQuery();
                    categoryQuery.setCode(bomItemEntity.getCategoryCode());
                    MateriaCategoryEntity materiaCategoryEntity = materiaCategoryService.find(categoryQuery, context).stream().findAny().orElseGet(() -> null);
                    if (!ObjectUtils.isEmpty(materiaCategoryEntity)){
                        materiaQuery.setCategoryId(materiaCategoryEntity.getId());
                    }
                }
                materiaEntity = materiaService.find(materiaQuery, context).stream().findAny().orElseGet(() -> null);
                if (ObjectUtils.isEmpty(materiaEntity)) {
                    returnStr.append("当前行号：" + bomItemEntity.getRowNum());
                    returnStr.append(String.format(" 物料不存在:%s", bomItemEntity.getMateriaName()));
                    returnStr.append("<br />");
                    fail++;
                    continue;
                }
            } else {
                returnStr.append("当前行号：" + bomItemEntity.getRowNum());
                returnStr.append(" 导入行物料编码和物料名称都为空!");
                returnStr.append("<br />");
                fail++;
                continue;
            }

            if (ObjectUtils.isEmpty(materiaEntity)) {
                returnStr.append("当前行号：" + bomItemEntity.getRowNum());
                returnStr.append(" 导入行物料为空!");
                returnStr.append("<br />");
                fail++;
                continue;
            }

            bomItemEntity.setMateriaId(materiaEntity.getId());
            bomItemEntity.setMateriaCode(materiaEntity.getCode());


            //判断是否有损耗率，如果没有设置则使用物料默认损耗率
            if (ObjectUtils.isEmpty(bomItemEntity.getLossRate())) {
                bomItemEntity.setLossRate(materiaEntity.getLossRate());
            }

            if (ObjectUtils.isEmpty(bomItemEntity.getUseNum())) {
                bomItemEntity.setUseNum(materiaEntity.getUseNum());
            }

            //补给方式
            if (!ObjectUtils.isEmpty(bomItemEntity.getSupplyTypeName())) {
                String keyByLoop = getKeyByLoop(matriaSupplyType, bomItemEntity.getSupplyTypeName());
                if (!ObjectUtils.isEmpty(keyByLoop)) {
                    bomItemEntity.setSupplyType(Integer.parseInt(keyByLoop));
                } else {
                    bomItemEntity.setSupplyType(materiaEntity.getSupplyType());
                }
            } else {
                bomItemEntity.setSupplyType(materiaEntity.getSupplyType());
            }

            //物料供应商，如果有则添加该字段校验

            if (!ObjectUtils.isEmpty(bomItemEntity.getSupplyName())) {
                SupplierQuery supplierQuery = new SupplierQuery();
                supplierQuery.setName(bomItemEntity.getSupplyName());

                SupplierEntity supplierEntity = supplierService.find(supplierQuery, context).stream().findAny().orElseGet(() -> null);
                if (ObjectUtils.isEmpty(supplierEntity)) {
                    returnStr.append("当前行号：" + bomItemEntity.getRowNum());
                    returnStr.append(String.format(" 供应商名称不存在:%s", bomItemEntity.getSupplyTypeName()));
                    returnStr.append("<br />");
                    fail++;
                    continue;
                }

                bomItemEntity.setSupplierId(supplierEntity.getId());
            }

            MateriaSupplierQuery materiaSupplierQuery = new MateriaSupplierQuery();

            materiaSupplierQuery.setMateriaId(materiaEntity.getId());
            MateriaSupplierEntity materiaSupplierEntity = materiaSupplierService.find(materiaSupplierQuery, context).stream().findAny().orElseGet(() -> null);
            if (ObjectUtils.isEmpty(materiaSupplierEntity)) {
                returnStr.append("当前行号：" + bomItemEntity.getRowNum());
                returnStr.append(String.format(" 物料代码:%s，名称:%s, 没有配置供应商:%s 无法导入", materiaEntity.getCode(), materiaEntity.getName(), bomItemEntity.getSupplyName()));
                returnStr.append("<br />");
                fail++;
                continue;
            }


            //查询物料bom是否存在bom如果有 则默认赋值一条bom
            MateriaBomQuery bomQuery = new MateriaBomQuery();
            bomQuery.setMateriaId(materiaEntity.getId());
            MateriaBomEntity bomEntity = this.find(bomQuery, context).stream().findFirst().orElseGet(() -> null);
            if (!ObjectUtils.isEmpty(bomEntity)) {
                bomItemEntity.setMateriaBomId(bomEntity.getId());
            }


            //查询是否已存在当前物料子项，如果存在则不添加

            MateriaBomItemQuery materiaBomItemQuery = new MateriaBomItemQuery();
            materiaBomItemQuery.setMateriaId(bomItemEntity.getMateriaId());
            materiaBomItemQuery.setBomId(bomItemEntity.getBomId());
            int count = materiaBomItemService.count(materiaBomItemQuery, context);
            if (count > 0) {
                returnStr.append("当前行号：" + bomItemEntity.getRowNum());
                returnStr.append(String.format(" 物料代码:%s，名称:%s, 已存在相同物料项，无法导入", materiaEntity.getCode(), materiaEntity.getName()));
                returnStr.append("<br />");
                fail++;
                continue;
            }

            bomItemEntity.setOrderNo(0L);
            bomItemEntity.setGroupName("");

            bomItemEntity.setCreateUser(context.getUser().getRealName());
            bomItemEntity.setCreateTime(new Date());
            bomItemEntity.setUpdateUser(context.getUser().getRealName());
            bomItemEntity.setUpdateTime(new Date());
            materiaBomItemService.save(bomItemEntity, context);
            suc++;

        }

        returnStr.append(String.format("产品项导入成功：%s条", suc));
        returnStr.append("<br/>");
        returnStr.append("<br/>");
        if (fail > 0) {
            returnStr.append(String.format("产品项导入失败：%s条", fail));
        }
        returnStr.append("</div>");
        return returnStr.toString();
    }

    @Override
    public String doExportBom(Long bomId, Context context) {
        String path = "/image/plm/materia/";
        String rootPath = this.filePath.endsWith("/") ? this.filePath : this.filePath + "/";
        String filePath = rootPath + (StringUtils.isEmpty(path) ? "" : path + "/");
        String newName = System.currentTimeMillis() + ".xls";
        filePath = filePath + newName;


        List<MateriaBomExportEntity> list = new ArrayList<>();
        Map<String, String> bomUseTypeMap = paramService.getParamByFirstOrganize("BomUseType");
        Map<String, String> matriaSupplyType = paramService.getParamByFirstOrganize("MatriaSupplyType");

        Map<String, String> supplyMap = supplierService.find(new SupplierQuery(), context).stream()
                .collect(Collectors.toMap(x -> x.getId().toString(), y -> y.getName(), (o, n) -> n));

        Map<String, String> unitOfMeasureMap = paramService.getParamByFirstOrganize(Constant.Param_MatriaUnitOfMeasure);

        ConfigFieldQuery configFieldQuery = new ConfigFieldQuery();
        configFieldQuery.setTableCode(Constant.PARAM_MORTALS_IOT_MATERIA_BOM_ITEM);
        configFieldQuery.setEnabled(YesNo.YES.getValue());
        Map<String, String> configFieldMap = configFieldService.find(configFieldQuery, context).stream().collect(Collectors.toMap(x -> x.getFieldCode(), y -> y.getFieldName(), (n, o) -> o));

        //获取bom30
        getBom(bomId, context, list, bomUseTypeMap, matriaSupplyType, supplyMap,unitOfMeasureMap);

        if (list.size() > 0) {
            FileOutputStream output = null;
            try {
                output = new FileOutputStream(filePath);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }

            Collections.reverse(list);
            IExcelUtil<MateriaBomExportEntity> eu = new ExcelUtils<>();
            eu.build(MateriaBomExportEntity.class).exportExcel(list, "物料BOM信息", output, configFieldMap);
        }


        return path + newName;
    }

    @Override
    public String doExportBomFlat(Long bomId, Context context) {
        String path = "/image/plm/materia/";
        String rootPath = this.filePath.endsWith("/") ? this.filePath : this.filePath + "/";
        String filePath = rootPath + (StringUtils.isEmpty(path) ? "" : path + "/");
        String newName = System.currentTimeMillis() + ".xls";
        filePath = filePath + newName;


        List<MateriaBomExportFlatEntity> list = new ArrayList<>();
        Map<String, String> bomUseTypeMap = paramService.getParamByFirstOrganize("BomUseType");
        Map<String, String> matriaSupplyType = paramService.getParamByFirstOrganize("MatriaSupplyType");

        Map<String, String> supplyMap = supplierService.find(new SupplierQuery(), context).stream()
                .collect(Collectors.toMap(x -> x.getId().toString(), y -> y.getName(), (o, n) -> n));

        Map<String, String> UnitOfMeasureMap = paramService.getParamByFirstOrganize(Constant.Param_MatriaUnitOfMeasure);

        ConfigFieldQuery configFieldQuery = new ConfigFieldQuery();
        configFieldQuery.setTableCode(Constant.PARAM_MORTALS_IOT_MATERIA_BOM_ITEM);
        configFieldQuery.setEnabled(YesNo.YES.getValue());
        Map<String, String> configFieldMap = configFieldService.find(configFieldQuery, context).stream().collect(Collectors.toMap(x -> x.getFieldCode(), y -> y.getFieldName(), (n, o) -> o));

        //获取bom
        getBomFlat(bomId, context, list, bomUseTypeMap, matriaSupplyType, supplyMap,UnitOfMeasureMap,configFieldMap);

        if (list.size() > 0) {
            FileOutputStream output = null;
            try {
                output = new FileOutputStream(filePath);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }

            Collections.reverse(list);
            IExcelUtil<MateriaBomExportFlatEntity> eu = new ExcelUtils<>();
            eu.build(MateriaBomExportFlatEntity.class).exportExcelFlat(list, "物料BOM信息", output, configFieldMap);
        }
        return path + newName;
    }

    private void getBom(Long bomId, Context context, List<MateriaBomExportEntity> list, Map<String, String> bomUseTypeMap, Map<String, String> matriaSupplyType, Map<String, String> supplyMap,Map<String, String> unitOfMeasureMap) {
        MateriaBomEntity materiaBomEntity = this.get(bomId, context);
        MateriaBomExportEntity bomExportEntity = new MateriaBomExportEntity();
        bomExportEntity.setVersion(materiaBomEntity.getVersion());
        bomExportEntity.setUseTypeName(bomUseTypeMap.getOrDefault(materiaBomEntity.getUseType().toString(), ""));
        bomExportEntity.setRemark(materiaBomEntity.getRemark());
        MateriaBomItemQuery materiaBomItemQuery = new MateriaBomItemQuery();
        materiaBomItemQuery.setBomId(materiaBomEntity.getId());
        List<MateriaBomItemEntity> itemEntities = materiaBomItemService.find(materiaBomItemQuery, context);
        List<MateriaBomItemExportEntity> items = itemEntities.stream().map(item -> {
            MateriaBomItemExportEntity itemExportEntity = new MateriaBomItemExportEntity();
            BeanUtils.copyProperties(item, itemExportEntity, BeanUtil.getNullPropertyNames(item));
            itemExportEntity.setPMateriaCode(materiaBomEntity.getMateriaCode());
            itemExportEntity.setPName(materiaBomEntity.getMateriaName());

            MateriaEntity materiaEntity = materiaService.get(item.getMateriaId(), context);
            itemExportEntity.setSpecModel(materiaEntity.getSpecModel());
            itemExportEntity.setUnitOfMeasure(unitOfMeasureMap.getOrDefault(materiaEntity.getUnitOfMeasure().toString(),""));
            itemExportEntity.setMateriaCode(item.getMateriaCode());
            itemExportEntity.setMateriaName(item.getMateriaName());
            itemExportEntity.setUseNum(item.getUseNum().toString());
            itemExportEntity.setLossRate(item.getLossRate().toString() + "%");
            itemExportEntity.setRequiredValue(YesNo.getByValue(item.getRequired()).getDesc());
            itemExportEntity.setSupplyTypeValue(matriaSupplyType.getOrDefault(item.getSupplyType().toString(), ""));
            itemExportEntity.setSupplierName(supplyMap.getOrDefault(item.getSupplierId() == null ? "" : item.getSupplierId().toString(), ""));
            MateriaBomEntity bomEntity = this.get(item.getMateriaBomId(), context);
            if (!ObjectUtils.isEmpty(bomEntity)) {
                itemExportEntity.setVersion(bomEntity.getVersion());
            }
            //设置扩展属性和名称

            if (item.getMateriaBomId() != null) {
                getBom(item.getMateriaBomId(), context, list, bomUseTypeMap, matriaSupplyType, supplyMap,unitOfMeasureMap);
            }
            return itemExportEntity;
        }).collect(Collectors.toList());

        bomExportEntity.setItems(items);

        list.add(bomExportEntity);
    }

    private void getBomFlat(Long bomId, Context context, List<MateriaBomExportFlatEntity> list, Map<String, String> bomUseTypeMap, Map<String, String> matriaSupplyType, Map<String, String> supplyMap, Map<String, String> UnitOfMeasureMap, Map<String, String> configFieldMap) {
        MateriaBomEntity materiaBomEntity = this.get(bomId, context);
        MateriaBomExportFlatEntity bomExportEntity = new MateriaBomExportFlatEntity();
        bomExportEntity.setBomName(materiaBomEntity.getMateriaName() + "BOM单");
        bomExportEntity.setCreateUser(materiaBomEntity.getCreateUser());
        bomExportEntity.setUseTypeName(bomUseTypeMap.getOrDefault(materiaBomEntity.getUseType().toString(), ""));
        bomExportEntity.setCreateDate(DateUtils.getStrDateTime(materiaBomEntity.getCreateTime()));
        MateriaBomItemQuery materiaBomItemQuery = new MateriaBomItemQuery();
        materiaBomItemQuery.setBomId(materiaBomEntity.getId());
        List<MateriaBomItemEntity> itemEntities = materiaBomItemService.find(materiaBomItemQuery, context);
        List<MateriaBomItemExportFlatEntity> items = itemEntities.stream().map(item -> {
            MateriaBomItemExportFlatEntity itemExportEntity = new MateriaBomItemExportFlatEntity();
            BeanUtils.copyProperties(item,itemExportEntity,BeanUtil.getNullPropertyNames(item));
            MateriaEntity materiaEntity = materiaService.get(item.getMateriaId(), context);
            MateriaCategoryEntity materiaCategoryEntity = materiaCategoryService.get(materiaEntity.getCategoryId(), context);
            itemExportEntity.setCategoryName(materiaCategoryEntity.getName());
            itemExportEntity.setMateriaName(item.getMateriaName());
            itemExportEntity.setSpecModel(materiaEntity.getSpecModel());

            itemExportEntity.setUnitOfMeasure(UnitOfMeasureMap.getOrDefault(materiaEntity.getUnitOfMeasure().toString(), ""));
            itemExportEntity.setUseNum(item.getUseNum().toString());
            itemExportEntity.setLossRate(item.getLossRate().toString() + "%");
            itemExportEntity.setRequiredValue(YesNo.getByValue(item.getRequired()).getDesc());
            itemExportEntity.setSupplyValue(matriaSupplyType.getOrDefault(item.getSupplyType().toString(), ""));
            itemExportEntity.setSupplierName(supplyMap.getOrDefault(item.getSupplierId() == null ? "" : item.getSupplierId().toString(), ""));

           itemExportEntity.setPic(filePath+materiaEntity.getMainPicUrl());

            itemExportEntity.setUnitPrice(materiaEntity.getCostPlan()==null?"":BigDecimal.valueOf(materiaEntity.getCostPlan()).divide(new BigDecimal(1000)).toString());

            return itemExportEntity;
        }).collect(Collectors.toList());

        bomExportEntity.setItems(items);

        list.add(bomExportEntity);
    }


    @Override
    public void copyBom(Long id, Context context) {
        MateriaBomEntity materiaBomEntity = this.get(id, context);

        if (ObjectUtils.isEmpty(materiaBomEntity)) {
            throw new AppException("未找到对应的Bom");
        }
        if (!materiaBomEntity.getStatus().equals(BomStatusEnum.BOM_PUBLISH.getValue())) {
            throw new AppException("复制的目标BOM未发布，禁止复制！");
        }

        //查询是否已经有一个同类的bom在编辑状态
        MateriaBomQuery materiaBomQuery = new MateriaBomQuery();
        materiaBomQuery.setMateriaId(materiaBomEntity.getMateriaId());
        materiaBomQuery.setUseType(materiaBomEntity.getUseType());
        MateriaBomEntity entity = this.find(materiaBomEntity, context).stream().filter(f -> f.getStatus().equals(BomStatusEnum.BOM_AUDIT.getValue()) || f.getStatus().equals(BomStatusEnum.BOM_EDIT.getValue())).findAny().orElseGet(() -> null);
        if (!ObjectUtils.isEmpty(entity)) {
            throw new AppException("复制的目标BOM存在编辑或者正在审核中的同类BOM，禁止复制！");
        }


        MateriaBomEntity bomEntity = new MateriaBomEntity();
        bomEntity.initAttrValue();
        BeanUtils.copyProperties(materiaBomEntity, bomEntity, new String[]{"id"});
        bomEntity.setStatus(BomStatusEnum.BOM_EDIT.getValue());
        bomEntity.setVersion("");

        MateriaBomTreeEntity bomTree = materiaBomTreeService.get(materiaBomEntity.getBomTreeId(), true);
        int count = getBomCountByTree(context, materiaBomEntity);
        //code自动生成
        bomEntity.setCode(bomTree.getCode() + "." + count);
        this.save(bomEntity, context);
        MateriaBomItemQuery materiaBomItemQuery = new MateriaBomItemQuery();
        materiaBomItemQuery.setBomId(materiaBomEntity.getId());

        materiaBomItemService.find(materiaBomItemQuery, context).stream().peek(item -> {
            MateriaBomItemEntity bomItemEntity = new MateriaBomItemEntity();
            bomItemEntity.initAttrValue();
            BeanUtils.copyProperties(item, bomItemEntity, new String[]{"id"});
            bomItemEntity.setBomId(bomEntity.getId());
            materiaBomItemService.save(bomItemEntity, context);

        }).count();

    }

    private int getBomCountByTree(Context context, MateriaBomEntity materiaBomEntity) {
        MateriaBomQuery bomQuery = new MateriaBomQuery();
        bomQuery.setBomTreeId(materiaBomEntity.getBomTreeId());
        return this.count(bomQuery, context);
    }

    private <K, V> K getKeyByLoop(Map<K, V> map, V value) {
        for (Map.Entry<K, V> entry : map.entrySet()) {
            if (Objects.equals(entry.getValue(), value)) {
                return entry.getKey();
            }
        }
        return null;
    }

}