package com.friday.custody.service.trustService.cmsc.service;

import com.alibaba.fastjson.JSON;
import com.friday.base.common.response.DubboResult;
import com.friday.custody.dao.*;
import com.friday.custody.dto.CmscAppSecretDTO;
import com.friday.custody.dto.CmscEmailDTO;
import com.friday.custody.dto.DataDictionaryTypeDto;
import com.friday.custody.dto.TenantEscrowAuthorizationInfoDto;
import com.friday.custody.entity.*;
import com.friday.custody.service.basicService.impl.*;
import com.friday.custody.service.trustService.citicZhongXin.service.OutsourceZhongXinService;
import com.friday.custody.service.trustService.cmsc.dto.*;
import com.friday.custody.service.trustService.cmsc.utils.CMSCGetDataUtil;
import com.friday.custody.service.trustService.htsc.dto.CustSharesDto;
import com.friday.custody.utils.*;
import com.google.gson.Gson;
import com.friday.custody.common.CustodyContants;
import com.friday.custody.enums.DataDictionaryTypeEnum;
import com.friday.custody.enums.EmailConfigPurposeEnum;
import com.friday.custody.service.basicService.DataDictionaryTypeCertificateCsdcService;
import com.friday.custody.service.basicService.DataDictionaryZxFndBasicInfoCyService;
import com.friday.custody.service.basicService.PullDataFailureLogService;
import com.friday.custody.service.logicService.DataDictionaryBasicService;
import com.friday.custody.service.trustService.OutsourceService;
import com.friday.custody.service.trustService.cmsc.utils.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.mail.*;
import javax.mail.internet.MimeMessage;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.friday.custody.common.CustodyContants.YEAR_MONTH_DAY_REGEX;

@Service
@Slf4j
public class OutsourceCmscServiceImpl implements OutsourceService {
    @Value("${custody.remote.url.cmsc.cmscUrlPrefix}")
    private String cmscUrlPrefix;

    @Autowired
    CMSCGetDataUtil cmscGetDataUtil;

    @Autowired
    DataDictionaryZxFndBasicInfoCyService dataDictionaryZxFndBasicInfoCyService;

    @Autowired
    HttpUtil httpUtil;

    @Value("${spring.profiles.active}")
    private String env;

    @Autowired
    private PullDataFailureLogService pullDataFailureLogService;

    @Autowired
    private DataDictionaryBasicService dataDictionaryBasicService;

    @Autowired
    private DataDictionaryTypeCustomerCsdcDetailsDao dataDictionaryTypeCustomerCsdcDetailsDao;

    @Autowired
    private DataDictionaryDurationCurrencyDetailsDao dataDictionaryDurationCurrencyDetailsDao;

    @Autowired
    private DataDictionaryTypeCertificateCsdcDetailsDao dataDictionaryTypeCertificateCsdcDetailsDao;

    @Autowired
    private DataDictionaryDividendWayDetailsDao dataDictionaryDividendWayDetailsDao;

    @Autowired
    private DataDictionarySellerDetailsDao dataDictionarySellerDetailsDao;

    @Autowired
    private FundInfoServiceImpl fundInfoService;
    @Autowired
    private InvestorInfoServiceImpl investorInfoService;
    @Autowired
    private InvestorBankInfoServiceImpl investorBankInfoService;
    @Autowired
    private AccountInfoServiceImpl accountInfoService;
    @Autowired
    private FundNetValueInfoServiceImpl fundNetValueInfoService;
    @Autowired
    private TgAccountBalanceInfoServiceImpl tgAccountBalanceInfoService;
    @Autowired
    private TgAccountSeqInfoServiceImpl tgAccountSeqInfoService;
    @Autowired
    private MjAccountBalanceInfoServiceImpl mjAccountBalanceInfoService;
    @Autowired
    private MjAccountSeqInfoServiceImpl mjAccountSeqInfoService;
    @Autowired
    private FundTradeInfoServiceImpl fundTradeInfoService;
    @Autowired
    private CustShareInfoServiceImpl custShareInfoService;
    @Resource(name = "pullDataThreadPool")
    private ExecutorService pullDataThreadPool;
    @Autowired
    DataDictionaryTypeCertificateCsdcService certificateCsdcService;
    @Autowired
    FundFeeDataInfoServiceImpl fundFeeDataInfoService;
    @Autowired
    private FundValueTableDataInfoServiceImpl fundValueTableDataInfoService;
    @Autowired
    DataDictionaryOpenStateServiceImpl openStateService;
    @Autowired
    FundOpenInfoServiceImpl fundOpenInfoService;

    @Autowired
    @Lazy
    OutsourceCmscServiceImpl outsourceCmscService;

    @Autowired
    DataDictionaryTypeOfFundValuationServiceImpl typeOfFundValuationService;
    @Autowired
    FundValuationServiceImpl fundValuationService;
    @Autowired
    OutsourceZhongXinService outsourceZhongXinService;


    @Override
    public R initTenantData(List<TenantEscrowAuthorizationInfoDto> tenants) {
        return null;
    }

    @Override
    public R initTenantDataSingle(TenantEscrowAuthorizationInfoDto tenant) {
        log.info("cmsc:initTenantDataSingle");
        getDataFromCMSC(tenant, 12);
        return R.ok("招商托管任务调用initTenantDataSingle!");
    }

    /**
     * 华泰托管专门用来初始化数据的
     *
     * @return
     */
    public R initDataByScheduled() {
        log.info("cmsc:initDataByScheduled");
        /*if (!taskQueue.isEmpty()) {
            taskQueue.forEach(this::getDataFromHTSC);
        }*/
        return R.ok("招商托管数据入库成功！");
    }

    public void getDataFromCMSCWithoutTgMj(TenantEscrowAuthorizationInfoDto tenant, int mouth) {
        String today = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
//        String companyId = "b759a8a2afef4a2788c5050b4ac6d9f6";
        CmscAppSecretDTO appSecretDTO = cmscGetDataUtil.getAppSecretDTO(tenant);
        String companyId = appSecretDTO.getCompanyId();
        String timeStramp = today;
        String trustNo = tenant.getTrustNo();
        System.out.println("timeStramp---->--->-->->" + timeStramp);


        log.info("招商每半天更新:0/8");
        //11(cust_share_seq_info) 1010
        processAccountInfoData(tenant, today, companyId, trustNo, mouth);
        log.info("招商每半天更新:1/8");

//        //8  募集户流水表（MJAccount_seq_info） 1002
//        processMJAccountSeqInfoData(tenant,today,companyId, trustNo,mouth);
//        log.info("progress:20%");

        //2 基金出资人信息表（investor_info） 1008   + 13 基金出资人银行账户信息表(investor_bank_info)
        processInvestorInfoData(tenant, today, companyId, trustNo, mouth);
        log.info("招商每半天更新:2/8");

//        //5  托管户银行账户余额信息表 (TGAccount_balance_info) 1010
//        processTGAccountBalanceInfoData(tenant,today,companyId, trustNo,mouth); //入参需要fundCode
//        log.info("progress:40%");

//        //6  托管户流水表 (TGAccount_seq_info)  1011
//        processTGAccountSeqInfoData(tenant,today,companyId, trustNo,mouth); //入参需要fundCode 单日
//        log.info("progress:50%");

        //6  托管户流水表 (TGAccount_seq_info)  1012
        processTGAccountSeqInfoData2(tenant, today, companyId, trustNo, mouth); //入参需要fundCode 历史
        log.info("招商每半天更新:3/8");

        //1 基金产品信息表（fund_info）   招商 1009
        processFundInfoData(tenant, today, companyId, trustNo, mouth);
        log.info("招商每半天更新:4/8");

        //4 基金持有信息表（cust_share_info） 1004
        processCustShareInfoData(tenant, today, companyId, trustNo, mouth);  //测试环境没有数据
        log.info("招商每半天更新:6/8");

        //9 基金交易确认信息表(fund_trade_info) 1006
        processFundTradeInfoData(tenant, today, companyId, trustNo, mouth);
        log.info("招商每半天更新:7/8");

        //基金费用数据表(fund_fee_data_info)
        outsourceCmscService.processFundFeeDataInfoData(tenant, today, companyId, trustNo, mouth);
        log.info("招商每半天更新:8/8");
//        //7  募集户银行账户余额信息表 (MJAccount_balance_info)  1001
//        processMJAccountBalanceInfoData(tenant,today,companyId, trustNo,mouth);
//        log.info("progress:100%");
    }

    public void getDataFromCMSC(TenantEscrowAuthorizationInfoDto tenant, int mouth) {
        String today = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
//        String companyId = "b759a8a2afef4a2788c5050b4ac6d9f6";
        String companyId = tenant.getCompanyId();
        String timeStramp = today;
        String trustNo = tenant.getTrustNo();
        System.out.println("timeStramp---->--->-->->" + timeStramp);


        log.info("招商初始化:开始");
        //11(account_info+MJAccount_balance_info) 1001
        processAccountInfoData(tenant, today, companyId, trustNo, mouth);
        log.info("招商初始化:1/12");

//        //8  募集户流水表（MJAccount_seq_info） 1002
        processMJAccountSeqInfoData(tenant, today, companyId, trustNo, mouth);
        log.info("招商初始化:2/12");

        //2 基金出资人信息表（investor_info） 1008   + 13 基金出资人银行账户信息表(investor_bank_info)
        processInvestorInfoData(tenant, today, companyId, trustNo, mouth);
        log.info("招商初始化:3/12");

        //5  托管户银行账户余额信息表 (TGAccount_balance_info) 1010
        processTGAccountBalanceInfoData(tenant, today, companyId, trustNo, mouth); //入参需要fundCode
        log.info("招商初始化:4/12");

        //6  托管户流水表 (TGAccount_seq_info)  1011
        processTGAccountSeqInfoData(tenant, today, companyId, trustNo, mouth); //入参需要fundCode 单日
        log.info("招商初始化:5/12");

        //6  托管户流水表 (TGAccount_seq_info)  1012
        processTGAccountSeqInfoData2(tenant, today, companyId, trustNo, mouth); //入参需要fundCode 历史
        log.info("招商初始化:6/12");

        //1 基金产品信息表（fund_info）   招商 1009
        processFundInfoData(tenant, today, companyId, trustNo, mouth);
        log.info("招商初始化:7/12");

        //        //3 基金净值信息表（fund_net_value_info）  1005
        processFundNetValueInfoData(tenant, today, companyId, trustNo, mouth);
        log.info("招商初始化:8/12");

        //基金费用数据表(fund_fee_data_info)
        outsourceCmscService.processFundFeeDataInfoData(tenant, today, companyId, trustNo, mouth);
        log.info("招商初始化:9/12");

        //4 基金持有信息表（cust_share_info） 1004
        processCustShareInfoData(tenant, today, companyId, trustNo, mouth);  //测试环境没有数据
        log.info("招商初始化:10/12");

        //9 基金交易确认信息表(fund_trade_info) 1006
        processFundTradeInfoData(tenant, today, companyId, trustNo, mouth);
        log.info("招商初始化:11/12");

//        //7  募集户银行账户余额信息表 (MJAccount_balance_info)  1001
        processMJAccountBalanceInfoData(tenant, today, companyId, trustNo, mouth);
        log.info("招商初始化:12/12");
        //TenantEscrowAuthorizationInfoDto tenant, String trustNo, int loopNum
        cmscContentsOfValuationSheetByEmail(tenant, trustNo, mouth);

    }


    private void sleep5Min(long l) {
        try {
            TimeUnit.MINUTES.sleep(l);
        } catch (InterruptedException e) {
            e.printStackTrace();
            Thread.currentThread().interrupt();
        };
    }

    public void processFundFeeDataInfoData(TenantEscrowAuthorizationInfoDto tenant, String today, String companyId, String trustNo, int mouth) {
        CmscAppSecretDTO appSecretDTO = cmscGetDataUtil.getAppSecretDTO(tenant);
        try {
            String startDate;
            String endDate;
            LocalDate localDate = LocalDate.now();
            LocalDate lastMonth;
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
            endDate = dateTimeFormatter.format(localDate);
            for (int i = 0; i < mouth; i++) {
                lastMonth = localDate.minusDays(30);
                startDate = dateTimeFormatter.format(lastMonth);
                String finalStartDate = startDate;
                String finalEndDate = endDate;
                int pageCount = 0;
                int pageNum = 0;
                int pageSize = 100;
                Map<String, Object> returnMap = new HashMap<>();
                try {
                    for (; ; ) {
                        pageNum++;
                        //1 封装请求参数
                        Map<String, Object> map = new HashMap<>();
                        map.put("beginDate", finalStartDate);
                        map.put("endDate", finalEndDate);
                        map.put("pageNumber", String.valueOf(pageNum));
                        map.put("pageSize", String.valueOf(pageSize));
                        Gson gson = new Gson();
                        String businessparam = gson.toJson(map);
                        log.info("businessparam" + businessparam);
                        String filePath = tenant.getFilePath();
                        String requestNo = "1020";
                        Map<String, Object> stringObjectMap =
                                httpUtil.sendMessage(appSecretDTO, requestNo, filePath, today, businessparam, CMFundFeeDataInfoDto.class, tenant);
                        pageCount = cmscGetDataUtil.getResultSize(returnMap, stringObjectMap, CMFundTradeInfoDto.class, tenant, requestNo, businessparam);
                        log.info("招商获取fundFeeDataInfo数据{}条", returnMap.size());
                        if (pageNum >= pageCount) {
                            break;
                        }

                    }
                } catch (Exception e) {
                    log.error("招商查询FundFeeDataInfo失败！", e);
                }
                if (PullDataFailureUtil.isFailed(returnMap)) {
                    pullDataFailureLogService.saveErrorData(tenant.getTenantName(), returnMap);
                    localDate = lastMonth;
                    endDate = startDate;
                    continue;
                }
                //2 封装数据 fund_fee_data_info
                List<FundFeeDataInfoEntity> entities = getFundFeeDataInfo(tenant, trustNo, returnMap);
                log.info("招商封装fundFeeDataInfo数据{}条", entities.size());
                //3 保存数据 fund_fee_data_info
                fundFeeDataInfoService.saveData(null, entities);
                localDate = lastMonth;
                endDate = startDate;
            }
        } catch (Exception e) {
            log.error("批量保存FundFeeDataInfo失败！", e);
        }
    }

    public List<FundFeeDataInfoEntity> getFundFeeDataInfo(TenantEscrowAuthorizationInfoDto tenant, String trustNo, Map<String, Object> fundFeeDataMap) {
        //获取字典
        //2.封装数据
        List<FundFeeDataInfoEntity> entityList = new ArrayList<>();
        if (!fundFeeDataMap.isEmpty()) {
            fundFeeDataMap.entrySet().forEach(entry -> {
                //CMFundFeeDataInfoDto dto = (CMFundFeeDataInfoDto) entry.getValue();
                CMFundFeeDataInfoDto dto = JSON.parseObject(JSON.toJSONString(entry.getValue()), CMFundFeeDataInfoDto.class);

                //根据获取到的inner_fund_code查询fundCode
                String fundCode = fundInfoService.getFundCodeByInnerFundCode(dto.getFundCode(), trustNo);
                //托管费
                entityList.add(FundFeeDataInfoEntity.builder()
                        .fundName(dto.getFundName())
                        .innerFundCode(dto.getFundCode())
                        .confirmDate(dto.getBusiDate())
                        .fareDebit(BigDecimalUtil.obj2BigDecimalTrunToZero(dto.getCustodianFeeJt()))
                        .fareCredit(BigDecimalUtil.obj2BigDecimalTrunToZero(dto.getCustodianFeeZf()))
                        .fareUnpaid(BigDecimalUtil.obj2BigDecimalTrunToZero(dto.getCustodianFeeYe()))
                        .subjectCode("TGF")
                        .subjectName("托管费")
                        .fundCode(fundCode)
                        .trustNo(trustNo)
                        .admin(tenant.getTenantName())
                        .createTime(new Date())
                        .updateTime(new Date())
                        .build());
                //运营服务费
                entityList.add(FundFeeDataInfoEntity.builder()
                        .fundName(dto.getFundName())
                        .innerFundCode(dto.getFundCode())
                        .confirmDate(dto.getBusiDate())
                        .fareDebit(BigDecimalUtil.obj2BigDecimalTrunToZero(dto.getOperationServiceFeeJt()))
                        .fareCredit(BigDecimalUtil.obj2BigDecimalTrunToZero(dto.getOperationServiceFeeZf()))
                        .fareUnpaid(BigDecimalUtil.obj2BigDecimalTrunToZero(dto.getOperationServiceFeeYe()))
                        .subjectCode("YYFWF")
                        .subjectName("运营服务费")
                        .fundCode(fundCode)
                        .trustNo(trustNo)
                        .admin(tenant.getTenantName())
                        .createTime(new Date())
                        .updateTime(new Date())
                        .build());
                //管理费
                entityList.add(FundFeeDataInfoEntity.builder()
                        .fundName(dto.getFundName())
                        .innerFundCode(dto.getFundCode())
                        .confirmDate(dto.getBusiDate())
                        .fareDebit(BigDecimalUtil.obj2BigDecimalTrunToZero(dto.getManagementFeeJt()))
                        .fareCredit(BigDecimalUtil.obj2BigDecimalTrunToZero(dto.getManagementFeeZf()))
                        .fareUnpaid(BigDecimalUtil.obj2BigDecimalTrunToZero(dto.getManagementFeeYe()))
                        .subjectCode("GLF")
                        .subjectName("管理费")
                        .fundCode(fundCode)
                        .trustNo(trustNo)
                        .admin(tenant.getTenantName())
                        .createTime(new Date())
                        .updateTime(new Date())
                        .build());
                //业绩报酬
                entityList.add(FundFeeDataInfoEntity.builder()
                        .fundName(dto.getFundName())
                        .innerFundCode(dto.getFundCode())
                        .confirmDate(dto.getBusiDate())
                        .fareDebit(BigDecimalUtil.obj2BigDecimalTrunToZero(dto.getPerformanceFeeJt()))
                        .fareCredit(BigDecimalUtil.obj2BigDecimalTrunToZero(dto.getPerformanceFeeZf()))
                        .fareUnpaid(BigDecimalUtil.obj2BigDecimalTrunToZero(dto.getPerformanceFeeYe()))
                        .subjectCode("YJBC")
                        .subjectName("业绩报酬")
                        .fundCode(fundCode)
                        .trustNo(trustNo)
                        .admin(tenant.getTenantName())
                        .createTime(new Date())
                        .updateTime(new Date())
                        .build());
                //销售服务费
                entityList.add(FundFeeDataInfoEntity.builder()
                        .fundName(dto.getFundName())
                        .innerFundCode(dto.getFundCode())
                        .confirmDate(dto.getBusiDate())
                        .fareDebit(BigDecimalUtil.obj2BigDecimalTrunToZero(dto.getSalesandServiceFeesJt()))
                        .fareCredit(BigDecimalUtil.obj2BigDecimalTrunToZero(dto.getSalesandServiceFeesZf()))
                        .fareUnpaid(BigDecimalUtil.obj2BigDecimalTrunToZero(dto.getSalesandServiceFeesYe()))
                        .subjectCode("XSF")
                        .subjectName("销售服务费")
                        .fundCode(fundCode)
                        .trustNo(trustNo)
                        .admin(tenant.getTenantName())
                        .createTime(new Date())
                        .updateTime(new Date())
                        .build());
                //投顾费
                entityList.add(FundFeeDataInfoEntity.builder()
                        .fundName(dto.getFundName())
                        .innerFundCode(dto.getFundCode())
                        .confirmDate(dto.getBusiDate())
                        .fareDebit(BigDecimalUtil.obj2BigDecimalTrunToZero(dto.getInvestmentConsultantFeeJt()))
                        .fareCredit(BigDecimalUtil.obj2BigDecimalTrunToZero(dto.getInvestmentConsultantFeeZf()))
                        .fareUnpaid(BigDecimalUtil.obj2BigDecimalTrunToZero(dto.getInvestmentConsultantFeeYe()))
                        .subjectCode("TGF2")
                        .subjectName("投顾费")
                        .fundCode(fundCode)
                        .trustNo(trustNo)
                        .admin(tenant.getTenantName())
                        .createTime(new Date())
                        .updateTime(new Date())
                        .build());
                //外包服务费
                entityList.add(FundFeeDataInfoEntity.builder()
                        .fundName(dto.getFundName())
                        .innerFundCode(dto.getFundCode())
                        .confirmDate(dto.getBusiDate())
                        .fareDebit(BigDecimalUtil.obj2BigDecimalTrunToZero(dto.getCustomerServiceFeeJt()))
                        .fareCredit(BigDecimalUtil.obj2BigDecimalTrunToZero(dto.getCustomerServiceFeeZf()))
                        .fareUnpaid(BigDecimalUtil.obj2BigDecimalTrunToZero(dto.getCustomerServiceFeeYe()))
                        .subjectCode("WBF")
                        .subjectName("外包服务费")
                        .fundCode(fundCode)
                        .trustNo(trustNo)
                        .admin(tenant.getTenantName())
                        .createTime(new Date())
                        .updateTime(new Date())
                        .build());
            });
        }
        return entityList;
    }

    /**
     * 第四张表
     *
     * @param tenant
     * @param trustNo
     * @param today
     */
    private void processCustShareInfoData(TenantEscrowAuthorizationInfoDto tenant, String today, String companyId, String trustNo, int mouth) {
        try {
            String startDate;
            String endDate;
            LocalDate localDate = LocalDate.now();
            LocalDate lastMonth;
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
            endDate = dateTimeFormatter.format(localDate);
            for (int i = 0; i < mouth; i++) {
                lastMonth = localDate.minusMonths(1);
                startDate = dateTimeFormatter.format(lastMonth);
                String finalStartDate = startDate;
                String finalEndDate = endDate;
                try {
                    //1 获取数据
                    Map<String, Object> fundValueData = cmscGetDataUtil.processCustShareInfoData(tenant, trustNo, cmscUrlPrefix, today, finalStartDate, finalEndDate, companyId);
                    if (PullDataFailureUtil.isFailed(fundValueData)) {
                        pullDataFailureLogService.saveErrorData(tenant.getTenantName(), fundValueData);
                        localDate = lastMonth;
                        endDate = startDate;
                        continue;
                    }
                    //2 封装数据 第四张表
                    List<CustShareInfoEntity> entities = getCustShareInfoData(tenant, trustNo, fundValueData);

                    //3 保存数据 第四张表
                    custShareInfoService.saveData(null, entities);
                } catch (Exception e) {
                    log.error("批量保存CustShareInfo失败！", e);
                }
                //
                localDate = lastMonth;
                endDate = startDate;

            }
        } catch (Exception e) {
            log.error("批量保存CustShareInfo失败！", e);
        }
        // TODO: 2022/1/13 加一个处理失败的日志统计表
    }

    private List<CustShareInfoEntity> getCustInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo, Map<String, Object> custSharesData) {
        Map<String, String> currencyDic = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.CURRENCY_SERVICE, trustNo);
        Map<String, String> dividendWayDic = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.DIVIDEND_WAY_SERVICE, trustNo);
        List<CustShareInfoEntity> result = new ArrayList<>();
        Map<String, String> sellerDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.SELLER_SERVICE, "招商证券");

        Date now = new Date();
        if (!custSharesData.isEmpty()) {
            custSharesData.entrySet().forEach(entry -> {
                ArrayList<Object> dtos = (ArrayList<Object>) entry.getValue();
                dtos.forEach(item -> {
                    CustSharesDto dto = (CustSharesDto) item;
                    String agency1 = MatchDataDictionaryKeyUtil.getKey(sellerDir, dto.getC_agencyno());

                    result.add(CustShareInfoEntity.builder()
                            .fundAcco(dto.getC_fundacco())
                            .fundName(dto.getC_fundname())
                            .agencyName(dto.getC_agencyname())
                            .agencyNo(agency1)
                            .tradeAcco(dto.getC_tradeacco())
                            .fundCode(dto.getC_fundcode())
                            .bonusMethod(MatchDataDictionaryKeyUtil.getKey(dividendWayDic, dto.getC_bonustype()))
                            .lastHoldShares(BigDecimalUtil.str2BigDecimal(dto.getF_lastholdshares()))
                            .totalProfit(BigDecimalUtil.str2BigDecimal(dto.getF_totalprofit()))
                            .realShares(BigDecimalUtil.str2BigDecimal(dto.getF_realshares()))
                            .currency(MatchDataDictionaryKeyUtil.getKey(currencyDic, dto.getF_currency().getCode()))
                            .frozenShares(BigDecimalUtil.str2BigDecimal(dto.getF_frozenshares()))
                            .trustNo(trustNo)
                            .admin(tenant.getTenantName())
                            //（根据此条响应数据的最新持有份额数last_hold_shares减去冻结份额frozen_shares得到可用份额作为此字段数据）需将String类型数据转换为Number(20,2)
                            .enableShares(BigDecimalUtil.str2BigDecimal(dto.getF_lastholdshares()))
                            .createTime(now)
                            .updateTime(now)
                            .build());
                });
            });
        }
        return result;
    }

    /**
     * 第八张表转化
     *
     * @param tenant
     * @param trustNo
     * @param cmMjAccountSeqInfoMap
     * @return
     */
    public List<MjAccountSeqInfoEntity> getMJAccountSeqInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo, Map<String, Object> cmMjAccountSeqInfoMap){
        log.info("MjAccountSeqInfoEntity" + JSON.toJSONString(cmMjAccountSeqInfoMap));

        Map<String, String> paymentDirectionDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.PAYMENT_DIRECTION_SERVICE, trustNo);


        List<MjAccountSeqInfoEntity> result = new ArrayList<>();
        if (!cmMjAccountSeqInfoMap.isEmpty()) {
            cmMjAccountSeqInfoMap.entrySet().forEach(entry -> {

                //CMMJAccountSeqInfoDto dto = (CMMJAccountSeqInfoDto) entry.getValue();
                CMMJAccountSeqInfoDto dto = JSON.parseObject(JSON.toJSONString(entry.getValue()), CMMJAccountSeqInfoDto.class);

                List<DataDictionaryTypeDto> dataDictionaryTypeDtos = dataDictionaryDurationCurrencyDetailsDao.selectDictionaryByTrustNo(trustNo);
                Map<String, String> currencyMap = dataDictionaryTypeDtos.stream().collect(Collectors.toMap(DataDictionaryTypeDto::getOriginValue, DataDictionaryTypeDto::getKeyStr));
                String currency = currencyMap.get(dto.getBz());

                log.info("mj_account_seq_info_currency原值={},映射值={}", dto.getBz(), currency);
                log.info("mj_account_seq_info_transferInOut原值={},映射值={}", dto.getSffx(), MatchDataDictionaryKeyUtil.getKey(paymentDirectionDir, dto.getSffx()));

                log.info("cpdm" + JSON.toJSONString(dto));
//                log.info("ERROR cpdm"+JSON.toJSONString(dto.getCpdm()));
                String jyrq = dto.getJyrq();
                if (jyrq != null && jyrq.length() > 10) {
                    jyrq = jyrq.substring(0, 10);
                }
                result.add(MjAccountSeqInfoEntity.builder()
                        .innerFundCode(dto.getCpdm())
                        .seqNo(dto.getLsh() != null && dto.getLsh().length() > 32 ? dto.getLsh().substring(0, 32) : dto.getLsh())
                        .account(dto.getBfzhh())
                        .accountName(dto.getBfzhmc())
                        .currency(currency)
                        .fundCode(dto.getCpdm())
                        .fundName(dto.getCpmc())
                        .opBankName(dto.getDsfkhhmc())
                        .opAccount(dto.getDsfzhh())
                        .opAccountName(dto.getDsfzhmc())
                        .amount(BigDecimalUtil.str2BigDecimal(dto.getJyje()))
                        .transferDate(jyrq)
                        .transferTime(dto.getJysj())
                        .bankName(dto.getMjhyh())
//                                .transferInOut(MatchDataDictionaryKeyUtil.getKey(paymentDirectionDir, dto.getSffx()))
                        .transferInOut(MatchDataDictionaryKeyUtil.getKey(paymentDirectionDir, dto.getSffx()))
                        .summary(dto.getYhbz())
                        .admin(tenant.getTenantName())
                        .trustNo(trustNo)
                        .createTime(new Date())
                        .updateTime(new Date())
                        .build());
            });
        }
        return result;
    }


    /**
     * 第七张表转化
     *
     * @param tenant
     * @param trustNo
     * @param cmFundTradeInfoDtoMap
     * @return
     */
    public List<MjAccountBalanceInfoEntity> getMJAccountBalanceInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo, Map<String, Object> cmFundTradeInfoDtoMap) {

        List<MjAccountBalanceInfoEntity> result = new ArrayList<>();
        if (!cmFundTradeInfoDtoMap.isEmpty()) {
            cmFundTradeInfoDtoMap.entrySet().forEach(entry -> {
                //CMMJAccountBalanceInfoDto dto = (CMMJAccountBalanceInfoDto) entry.getValue();
                CMMJAccountBalanceInfoDto dto = JSON.parseObject(JSON.toJSONString(entry.getValue()), CMMJAccountBalanceInfoDto.class);


                List<DataDictionaryTypeDto> dataDictionaryTypeDtos = dataDictionaryDurationCurrencyDetailsDao.selectDictionaryByTrustNo(trustNo);
                Map<String, String> currencyMap = dataDictionaryTypeDtos.stream().collect(Collectors.toMap(DataDictionaryTypeDto::getOriginValue, DataDictionaryTypeDto::getKeyStr));
                String currency = currencyMap.get(dto.getBz());

                log.info("mj_account_balance_info_currency原值={},映射值={}", dto.getBz(), currency);
                MjAccountBalanceInfoEntity build = MjAccountBalanceInfoEntity.builder()
//                                .currency(currency)
                        .currency(currency)
                        .summary(dto.getClsm())
                        .updateDate(dto.getGxsj())
                        .availableBalance(BigDecimalUtil.str2BigDecimal(dto.getKyye()))
                        .bankAcco(dto.getZhh())
                        .accoBalance(BigDecimalUtil.str2BigDecimal(dto.getZhye()))
                        .admin(tenant.getTenantName())
                        .createTime(new Date())
                        .updateTime(new Date())
                        .trustNo(trustNo)
                        .updateTime(new Date())
                        .build();
                result.add(build);
                log.info("mjAccountBalanceInfo数据变成的entity" + JSON.toJSONString(build));

            });
        }
        return result;
    }

    /**
     * 第九张表转化
     *
     * @param tenant
     * @param trustNo
     * @param cmFundTradeInfoDtoMap
     * @return
     */
    public List<FundTradeInfoEntity> getFundTradeInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo, Map<String, Object> cmFundTradeInfoDtoMap) {
        log.info("FundTradeInfoEntity" + JSON.toJSONString(cmFundTradeInfoDtoMap));

        Map<String, String> businessTypeDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.BUSINESS_NAME_SERVICE, trustNo);
        Map<String, String> confirmStatusDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.CONFIRM_STATUS_SERVICE, trustNo);
        Map<String, String> sellerDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.SELLER_SERVICE, "招商证券");


        List<FundTradeInfoEntity> result = new ArrayList<>();
        if (!cmFundTradeInfoDtoMap.isEmpty()) {
            cmFundTradeInfoDtoMap.entrySet().forEach(entry -> {
                //CMFundTradeInfoDto dto = (CMFundTradeInfoDto) entry.getValue();
                CMFundTradeInfoDto dto = JSON.parseObject(JSON.toJSONString(entry.getValue()), CMFundTradeInfoDto.class);

                String fundCode = dto.getFundCode();
                String fundCodeByFundCode = getFundCodeByFundCode(fundCode);

                String agency1 = MatchDataDictionaryKeyUtil.getKey(sellerDir, dto.getDistributorCode());

                log.info("fund_trade_info agencyNo原值=" + dto.getDistributorCode() + "映射值=" + agency1);
                log.info("fund_trade_info confirmStatus原值=" + dto.getRemark2() + "映射值=" + MatchDataDictionaryKeyUtil.getKey(confirmStatusDir, dto.getRemark2()));
                log.info("fund_trade_info businessName原值=" + dto.getBusinessCode() + "映射值=" + MatchDataDictionaryKeyUtil.getKey(businessTypeDir, dto.getBusinessCode()));


                result.add(FundTradeInfoEntity.builder()
                        .innerFundCode(dto.getFundCode())
                        .fundAcco(dto.getTaAccountId())
                        .tradeAcco(dto.getTransactionAccountId())
                        .fundName(dto.getFundName())
                        .fundCode(fundCodeByFundCode)
//                                .businessName(MatchDataDictionaryKeyUtil.getKey(businessTypeDir,dto.getBusinessCode()))
                        .businessName(MatchDataDictionaryKeyUtil.getKey(businessTypeDir, dto.getBusinessCode()))
                        .applyBalance(dto.getApplicationAmount())
                        .applyShares(dto.getApplicationVol())
                        .requestDate(dto.getTransactionDate())
                        .netValue(dto.getNav())
                        .confirmDate(dto.getTransactionCfmDate())
                        .confirmShares(dto.getConfirmedVol())
                        .confirmBalance(dto.getConfirmedAmount())
                        .confirmNavVol(dto.getConfirmedNavVol())
                        .tradeFare(dto.getCharge())
                        .profitBalance(dto.getPerformance())
                        .agencyNo(agency1)
                        .agencyName(dto.getDistributorName())
                        .cserialNo(dto.getRemark1())
//                                .confirmStatus(MatchDataDictionaryKeyUtil.getKey(confirmStatusDir,dto.getRemark2()))
                        .confirmStatus(MatchDataDictionaryKeyUtil.getKey(confirmStatusDir, dto.getRemark2()))
                        .summary(dto.getNote())
                        .requestNo(dto.getOrigDefNo())
                        .admin(tenant.getTenantName())
                        .trustNo(trustNo)
                        .createTime(new Date())
                        .updateTime(new Date())
                        .build());
            });
        }
        return result;
    }

    private String getFundCodeByFundCode(String fundCode) {
        return fundInfoService.getFundCodeByFundCode(fundCode);
    }

    /**
     * 第三张表转化
     *
     * @param tenant
     * @param trustNo
     * @param fundValueData
     * @return
     */
    public List<FundNetValueInfoEntity> getFundNetValueInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo, Map<String, Object> fundValueData) {

        List<FundNetValueInfoEntity> result = new ArrayList<>();
        if (!fundValueData.isEmpty()) {
            fundValueData.entrySet().forEach(entry -> {
                //CMFundNetValueInfoDto dto = (CMFundNetValueInfoDto) entry.getValue();
                CMFundNetValueInfoDto dto = JSON.parseObject(JSON.toJSONString(entry.getValue()), CMFundNetValueInfoDto.class);


                String fundCode = dto.getFundCode();
                String fundName = dto.getFundName();
                if (StringUtils.isBlank(fundName)) {
                    fundName = "null";
                }
                //设置fundCode
                log.info("getFundNetValueInfoData：上游拿到的fundCode={},fundName={}", fundCode, fundName);
                String fundInfoFundCode = "";
                if (StringUtils.isBlank(fundName)) {
                    log.error("当前1005接口上线数据为{},fundName为blank:{}", JSON.toJSONString(dto), fundName);
                } else {
                    String substring = fundName.substring(fundName.length() - 1);

                    Matcher matcher = letterPattern.matcher(substring);
                    boolean lastCharIsLetter = matcher.find();

                    if (lastCharIsLetter) {
                        String fundNamePrefix = fundName.substring(0, fundName.length() - 1);
                        log.info("fundName为：{}末尾为字母，去掉字母后为{}去数据库查", fundName, fundNamePrefix);
                        fundInfoFundCode = getFundCodeByFundName(fundNamePrefix, tenant);
                        log.info("查询数据库、上游、字典表拿到的fundCode为{}", fundInfoFundCode);
                    } else {
                        fundInfoFundCode = fundCode;
                    }
                }

                log.info("getFundInfoData:入参fundCode{},入参fundName{},出参fundInfoFundCode{}", fundCode, fundName, fundInfoFundCode);

                result.add(FundNetValueInfoEntity.builder()
                        .innerFundCode(dto.getFundCode())
                        .fundCode(fundInfoFundCode)
                        .fundName(dto.getFundName())
                        .netValueDate(dto.getNavDate())
                        .shares(BigDecimalUtil.str2BigDecimalDefaultZero(dto.getAssetVol()))
                        .assetValue(BigDecimalUtil.str2BigDecimalDefaultZero(dto.getAssetNav()))
                        .totalAsset(BigDecimalUtil.str2BigDecimalDefaultZero(dto.getTotalAsset()))
                        .netValue(BigDecimalUtil.str2BigDecimal(dto.getNav(), 4))
                        .totalNetValue(BigDecimalUtil.str2BigDecimal(dto.getAccumulativeNav(), 4))
                        .admin(tenant.getTenantName())
                        .trustNo(trustNo)
                        .createTime(new Date())
                        .updateTime(new Date())
                        .build());
            });
        }
        return result;
    }

    /**
     * 第四张表转化
     *
     * @param tenant
     * @param trustNo
     * @param fundValueData
     * @return
     */
    public List<CustShareInfoEntity> getCustShareInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo, Map<String, Object> fundValueData) {
        /*
        Map<String, String> currencyDic = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.CURRENCY_SERVICE, trustNo);
        Map<String, String> fundClassificationLogoDic = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.FUND_CLASSIFICATION_LOGO_SERVICE, trustNo);
        */

        Map<String, String> sellerDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.SELLER_SERVICE, "招商证券");


        List<DataDictionaryTypeDto> dataDictionaryTypeDtos = dataDictionaryDividendWayDetailsDao.selectDictionaryByTrustNo(trustNo);
        Map<String, String> collect = dataDictionaryTypeDtos.stream().collect(Collectors.toMap(DataDictionaryTypeDto::getOriginValue, DataDictionaryTypeDto::getKeyStr));
        List<DataDictionaryTypeDto> dataDictionaryTypeDtos1 = dataDictionarySellerDetailsDao.selectDictionaryByTrustNo(trustNo);
        Map<String, String> collect1 = dataDictionaryTypeDtos1.stream().collect(Collectors.toMap(DataDictionaryTypeDto::getOriginValue, DataDictionaryTypeDto::getKeyStr));

        List<CustShareInfoEntity> result = new ArrayList<>();
        if (!fundValueData.isEmpty()) {
            fundValueData.entrySet().forEach(entry -> {
                //CMCustShareInfoDto dto = (CMCustShareInfoDto) entry.getValue();
                CMCustShareInfoDto dto = JSON.parseObject(JSON.toJSONString(entry.getValue()), CMCustShareInfoDto.class);

                String fundCode = dto.getFundCode();
                String fundCodeByFundCode = getFundCodeByFundCode(fundCode);
                log.info("getFundCodeByFundCode入参" + fundCode + " fundCodeByFundCode出参" + fundCodeByFundCode);
                if (StringUtils.isBlank(fundCodeByFundCode)) {
                    fundCodeByFundCode = fundCode;
                }

                String bonusMethod = collect.get(dto.getDefdividendMethod());
                String agencyNo = collect1.get(dto.getDistributorCode());

                String agency1 = MatchDataDictionaryKeyUtil.getKey(sellerDir, dto.getDistributorCode());
                log.info("cust_share_info的 agencyNo原值=" + dto.getDistributorCode() + "映射值=" + agency1);
                log.info("cust_share_info的 bonusMethod原值=" + dto.getDefdividendMethod() + "映射值=" + bonusMethod);

                //处理 share_ratio 字段
                BigDecimal shareRatio = null;
                FundNetValueInfoEntity newestByInnerFundCodeAndFundName = fundNetValueInfoService.getNewestByInnerFundCodeAndFundName(fundCode, dto.getFundName(), trustNo);
                if (newestByInnerFundCodeAndFundName != null) {
                    BigDecimal shares = newestByInnerFundCodeAndFundName.getShares();

                    BigDecimal lastHoldShares = dto.getTotalFundVol();
                    if (lastHoldShares == null || shares == null || shares.equals(new BigDecimal("0"))) {
                        log.error("getCustShareInfoData计算share_ratio参数异常lastHoldShares={}，shares={}", lastHoldShares, shares);
                    } else {
                        BigDecimal divide = lastHoldShares.divide(shares, 6, RoundingMode.HALF_DOWN);
                        shareRatio = divide.multiply(new BigDecimal("100")).setScale(4, RoundingMode.HALF_DOWN);
                    }

                } else {
                    log.error("cust_share_info设置share_ratio字段时没有找到相应的fund_net_value_info记录");
                }

                log.info("cust_share_info的 dto.getFundVolDate()" + dto.getFundVolDate());
                //处理updateDate
                SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
                SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String updateDate = null;
                if (!StringUtils.isEmpty(dto.getFundVolDate())) {
                    try {
                        Date parse = sdf.parse(dto.getFundVolDate());
                        updateDate = sdf1.format(parse);
                    } catch (ParseException e) {
                        e.printStackTrace();
                        log.error("时间转化失败！", e);
                    }
                }
                result.add(CustShareInfoEntity.builder()
                        .innerFundCode(dto.getFundCode())
                        .fundAcco(dto.getTaAccountId())
                        .tradeAcco(dto.getTransactionAccountId())
                        .fundName(dto.getFundName())
                        .fundCode(fundCodeByFundCode)
                        .updateDate(updateDate)
                        .lastHoldShares(dto.getTotalFundVol())
                        .enableShares(dto.getApplicationVol())
                        .frozenShares(dto.getFrozenVol())
                        .bonusMethod(bonusMethod)
                        .agencyNo(agency1)
                        .agencyName(dto.getDistributorName())
                        .shareRatio(shareRatio)
                        .admin(tenant.getTenantName())
                        .trustNo(trustNo)
                        .createTime(new Date())
                        .updateTime(new Date())
                        .build());
            });
        }
        return result;
    }

    /**
     * 第一张表 1 基金产品信息表（fund_info）
     *
     * @param tenant
     * @param today
     * @param today
     */
    private void processFundInfoData(TenantEscrowAuthorizationInfoDto tenant, String today, String companyId, String trustNo, int mouth) {
        try {
            String startDate;
            String endDate;
            LocalDate localDate = LocalDate.now();
            LocalDate lastMonth;
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
            endDate = dateTimeFormatter.format(localDate);
            for (int i = 0; i < mouth; i++) {
                lastMonth = localDate.minusMonths(1);
                startDate = dateTimeFormatter.format(lastMonth);
                String finalStartDate = startDate;
                String finalEndDate = endDate;
                try {
                    //1 获取数据
                    Map<String, Object> fundValueData = cmscGetDataUtil.processFundInfoData(tenant, trustNo, cmscUrlPrefix, today, finalStartDate, finalEndDate, companyId);
                    if (PullDataFailureUtil.isFailed(fundValueData)) {
                        pullDataFailureLogService.saveErrorData(tenant.getTenantName(), fundValueData);
                        localDate = lastMonth; //fixm
                        endDate = startDate;
                        continue;
                    }
                    //2 封装数据 第一张表
                    List<FundInfoEntity> entities = getFundInfoData(tenant, trustNo, fundValueData, cmscUrlPrefix, today, companyId);
                    //2 封装数据 fund_open_info
                    List<FundOpenInfoEntity> fundOpenInfoEntities = getFundOpenInfo(tenant, trustNo, fundValueData);
                    log.info("cmsc : processFundInfoData封装数据fundOpenInfo  dataSize = {}", fundOpenInfoEntities.size());
                    fundOpenInfoService.saveData(null, fundOpenInfoEntities);

                    //3 保存数据 第一张表
                    fundInfoService.saveData(null, entities);
                } catch (Exception e) {
                    log.error("批量保存FundInfo失败！", e);
                }
                localDate = lastMonth;
                endDate = startDate;
            }
        } catch (Exception e) {
            log.error("批量保存fundIno失败！", e);
        }
    }

    public List<FundOpenInfoEntity> getFundOpenInfo(TenantEscrowAuthorizationInfoDto tenant, String trustNo, Map<String, Object> fundValueData) {
        //获取数据字典
        //开放日类型字典
        Map<String, String> typeOfOpenDayDic = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.TYPE_OF_OPEN_DAY_SERVICE, trustNo);
        //发放状态字典
        Map<String, Map<String, String>> openStateDic = openStateService.queryOpenStateWithDetail(trustNo);
        //封装数据
        List<FundOpenInfoEntity> entityList = new ArrayList<>();
        fundValueData.entrySet().forEach(entry -> {
            //CMPrdInfoDto dto = (CMPrdInfoDto) entry.getValue();
            CMPrdInfoDto dto = JSON.parseObject(JSON.toJSONString(entry.getValue()), CMPrdInfoDto.class);
            //开放类型转义
            String openType = MatchDataDictionaryKeyUtil.getKey(typeOfOpenDayDic, dto.getOpenType());
            //获取fundCode
            String fundCode = dto.getFundCode();
            String fundName = dto.getFundName();
            if (StringUtils.isBlank(fundName)) {
                fundName = "null";
            }
            //设置fundCode
            log.info("getFundInfoData：上游拿到的fundCode={},fundName={}", fundCode, fundName);
            String fundInfoFundCode = "";
            if (StringUtils.isBlank(fundName)) {
                log.error("当前1009接口上线数据为{},fundName为blank:{}", JSON.toJSONString(dto), fundName);
            } else {
                //判断fundName是否以字母结尾
                String substring = fundName.substring(fundName.length() - 1);
                Matcher matcher = letterPattern.matcher(substring);
                boolean lastCharIsLetter = matcher.find();
                //如果以字母结尾
                if (lastCharIsLetter) {
                    String fundNamePrefix = fundName.substring(0, fundName.length() - 1);
                    log.info("fundName为：{}末尾为字母，去掉字母后为{}去数据库查", fundName, fundNamePrefix);
                    fundInfoFundCode = getFundCodeByFundName(fundNamePrefix, tenant);
                    log.info("查询数据库、上游、字典表拿到的fundCode为{}", fundInfoFundCode);
                } else {//如果不以字母结尾，fundCode和innerFundCode取值一样
                    fundInfoFundCode = fundCode;
                }
            }
            log.info("getFundInfoData:入参fundCode{},入参fundName{},出参fundInfoFundCode{}", fundCode, fundName, fundInfoFundCode);
            entityList.add(FundOpenInfoEntity.builder()
                    .innerFundCode(dto.getFundCode())
                    .fundName(fundName)
                    .fundOpenDate(dto.getOpenDate())
                    .openType(openType)
                    .openStatus(MatchDataDictionaryKeyUtil.getKey(openType, openStateDic, dto.getIfTempOpen()))
                    //.ifFixedTime(Integer.parseInt(dto.getIfFixedTime()))
                    .ifFixedTime(dto.getIfFixedTime().equals("否")?0:1)
                    .fundCode(fundCode)
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(new Date())
                    .updateTime(new Date())
                    .build());
        });
        return entityList;
    }

    /**
     * 第八张表
     *
     * @param tenant
     * @param today
     * @param companyId
     * @param trustNo
     */
    private void processMJAccountSeqInfoData(TenantEscrowAuthorizationInfoDto tenant, String today, String companyId, String trustNo, int mouth) {
        try {
            String startDate;
            String endDate;
            LocalDate localDate = LocalDate.now();
            LocalDate lastMonth;
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
            endDate = dateTimeFormatter.format(localDate);
            for (int i = 0; i < mouth; i++) {

                lastMonth = localDate.minusMonths(1);
                startDate = dateTimeFormatter.format(lastMonth);
                String finalStartDate = startDate;
                String finalEndDate = endDate;
//                CompletableFuture.supplyAsync(() -> { //fixme
                try {
                    //1 获取数据
                    Map<String, Object> mjAccountSeqInfoData = cmscGetDataUtil.processMJAccountSeqInfoData(tenant, trustNo, cmscUrlPrefix, today, finalStartDate, finalEndDate, companyId);
                    if (PullDataFailureUtil.isFailed(mjAccountSeqInfoData)) {
                        pullDataFailureLogService.saveErrorData(tenant.getTenantName(), mjAccountSeqInfoData);
                        localDate = lastMonth;  //fixme
                        endDate = startDate; //fixme
                        continue;  //fixme
//                            return null; //fixme
                    }
                    //2 封装数据 第八张表
                    List<MjAccountSeqInfoEntity> entities = getMJAccountSeqInfoData(tenant, trustNo, mjAccountSeqInfoData);

                    //3 保存数据 第八张表
                    mjAccountSeqInfoService.saveData(null, entities);
                } catch (Exception e) {
                    log.error("批量保存MJAccountSeqInfo失败！", e);
                }
                // TODO: 2022/1/13 加一个处理失败的日志统计表
//                    return null; //fixme
//                }, pullDataThreadPool); //fixme
                localDate = lastMonth;
                endDate = startDate;
            }
        } catch (Exception e) {
            log.error("批量保存MJAccountSeqInfo失败！", e);
        }
        // TODO: 2022/1/13 加一个处理失败的日志统计表
    }

    /**
     * 第五张表
     *
     * @param tenant
     * @param today
     * @param companyId
     * @param trustNo
     */
    private void processTGAccountBalanceInfoData(TenantEscrowAuthorizationInfoDto tenant, String today, String companyId, String trustNo, int mouth) {
        try {
            List<String> fundCodeList = accountInfoService.getFundCodeList(trustNo, tenant.getTenantName());
            log.info("fundCode查询情况为：" + JSON.toJSONString(fundCodeList));
            //1 获取数据
            for (String fundCode : fundCodeList) {
                if (StringUtils.isBlank(fundCode)) {
                    continue;
                }
                Map<String, Object> tgAccountBalanceInfoData = cmscGetDataUtil.processTGAccountBalanceInfoData(tenant, trustNo, cmscUrlPrefix, today, companyId, fundCode);
                //Object data = tgAccountBalanceInfoData.get("data");
                if (PullDataFailureUtil.isFailed(tgAccountBalanceInfoData)) {
                    String errorJson = JSON.toJSONString(tgAccountBalanceInfoData);
                    log.error("processTGAccountBalanceInfoData:{}",errorJson);
                    if (errorJson.contains("该产品不存在")) {
                        log.error("processTGAccountBalanceInfoData_该产品不存在!" + errorJson);
                        continue;
                    }
                    pullDataFailureLogService.saveErrorData(tenant.getTenantName(), tgAccountBalanceInfoData);
                    throw new IllegalArgumentException("获取数据异常");
                }
                //2 封装数据 第五张表
                List<TgAccountBalanceInfoEntity> entities = getTgAccountBalanceInfoData(tenant, trustNo, tgAccountBalanceInfoData);

                //3 保存数据 第五张表
                tgAccountBalanceInfoService.saveData(null, entities);

                //2 封装数据 第五张表
                List<AccountInfoEntity> entitiesAccountInfo = getAccountInfoData3(tenant, trustNo, tgAccountBalanceInfoData);

                //3 保存数据 第五张表
                accountInfoService.saveData(null, entitiesAccountInfo);

            }
        } catch (Exception e) {
            log.error("批量保存fundIno失败！", e);
        }
        // TODO: 2022/1/13 加一个处理失败的日志统计表
    }

    /**
     * 第六张表(1)
     *
     * @param tenant
     * @param today
     * @param companyId
     * @param trustNo
     */
    private void processTGAccountSeqInfoData(TenantEscrowAuthorizationInfoDto tenant, String today, String companyId, String trustNo, int mouth) {
        try {
            List<String> fundCodeList = accountInfoService.getFundCodeList(trustNo, tenant.getTenantName());
            log.info("fundCode查询情况为：" + JSON.toJSONString(fundCodeList));
            for (String fundCode : fundCodeList) {
                try {
                    if (StringUtils.isBlank(fundCode)) {
                        continue;
                    }
                    Map<String, Object> tgAccountSeqInfoData = cmscGetDataUtil.processTGAccountSeqInfoData(tenant, trustNo, cmscUrlPrefix, today, companyId, fundCode);
                    if (PullDataFailureUtil.isFailed(tgAccountSeqInfoData)) {
                        String errorJson = JSON.toJSONString(tgAccountSeqInfoData);
                        if (errorJson.contains("该产品不存在")) {
                            continue;
                        }
                        pullDataFailureLogService.saveErrorData(tenant.getTenantName(), tgAccountSeqInfoData);
                        throw new IllegalArgumentException("招商获取数据异常");
                    }
                    //2 封装数据 第六张表
                    List<TgAccountSeqInfoEntity> entities = getTgAccountSeqInfoData(tenant, trustNo, tgAccountSeqInfoData);

                    //3 保存数据 第六张表
                    tgAccountSeqInfoService.saveData(null, entities);
                } catch (Exception e) {
                    log.error("processTGAccountSeqInfoData当fundCode为" + fundCode + "时，发生错误", fundCode, e);
                }
                // TODO: 2022/1/13 加一个处理失败的日志统计表

            }
        } catch (Exception e) {
            log.error("批量保存fundIno失败！", e);
        }
        // TODO: 2022/1/13 加一个处理失败的日志统计表
    }


    /**
     * 第六张表(2)
     *
     * @param tenant
     * @param today
     * @param companyId
     * @param trustNo
     */
    private void processTGAccountSeqInfoData2(TenantEscrowAuthorizationInfoDto tenant, String today, String companyId, String trustNo, int mouth) {

        List<String> fundCodeList = accountInfoService.getFundCodeList(trustNo, tenant.getTenantName());
        log.info("TGAccountSeqInfo_得到的fundCodeList:" + JSON.toJSONString(fundCodeList));
        if (fundCodeList != null && fundCodeList.size() > 0) {

            for (String fundCode : fundCodeList) {
                if (StringUtils.isBlank(fundCode)) {
                    continue;
                }
                try {
                    String startDate;
                    String endDate;
                    LocalDate localDate = LocalDate.now();
                    LocalDate lastMonth;
                    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
                    endDate = dateTimeFormatter.format(localDate);
                    for (int i = 0; i < mouth; i++) {

                        lastMonth = localDate.minusMonths(1);
                        startDate = dateTimeFormatter.format(lastMonth);
                        String finalStartDate = startDate;
                        String finalEndDate = endDate;
//                    CompletableFuture.supplyAsync(() -> {  //fixme
                        try {
                            //1 获取数据
                            Map<String, Object> tgAccountSeqInfoDataData2 = cmscGetDataUtil.processTGAccountSeqInfoDataData2
                                    (tenant, fundCode, finalStartDate, finalEndDate, today);
                            if (PullDataFailureUtil.isFailed(tgAccountSeqInfoDataData2)) {
                                pullDataFailureLogService.saveErrorData(tenant.getTenantName(), tgAccountSeqInfoDataData2);
//                                return null; //fixme
                                localDate = lastMonth; //fixme
                                endDate = startDate; //fixme
                                continue; //fixme

                            }
                            //2 封装数据
                            List<TgAccountSeqInfoEntity> entities = getTgAccountSeqInfoData(tenant, trustNo, tgAccountSeqInfoDataData2);

                            //3 保存数据
                            tgAccountSeqInfoService.saveData(null, entities);
                        } catch (Exception e) {
                            log.error("批量保存fundNetValueInfo失败！", e);
                        }
                        // TODO: 2022/1/13 加一个处理失败的日志统计表
//                        return null;  //fixme
//                    }, pullDataThreadPool);   //fixme
                        localDate = lastMonth;
                        endDate = startDate;
                    }
                    // TODO: 2022/1/13 加一个处理失败的日志统计表
                } catch (Exception e) {
                    log.error("批量保存FundNetValueInfo失败！", e);
                }
            }
        }

    }

    /**
     * 第七张表
     *
     * @param tenant
     * @param today
     * @param companyId
     * @param trustNo
     */
    private void processMJAccountBalanceInfoData(TenantEscrowAuthorizationInfoDto tenant, String today, String companyId, String trustNo, int mouth) {
        try {
            Map<String, Object> tgAccountSeqInfoData = cmscGetDataUtil.processMJAccountBalanceInfoData(tenant, trustNo, cmscUrlPrefix, today, companyId);
            if (PullDataFailureUtil.isFailed(tgAccountSeqInfoData)) {
                pullDataFailureLogService.saveErrorData(tenant.getTenantName(), tgAccountSeqInfoData);
                throw new IllegalArgumentException("获取数据异常");
            }
            //2 封装数据 第七张表
            List<MjAccountBalanceInfoEntity> entities = getMJAccountBalanceInfoData(tenant, trustNo, tgAccountSeqInfoData);

            //3 保存数据 第七张表
            mjAccountBalanceInfoService.saveData(null, entities);

        } catch (Exception e) {
            log.error("processMJAccountBalanceInfoData！", e);
        }
        // TODO: 2022/1/13 加一个处理失败的日志统计表
    }


    /**
     * 第十一张表
     *
     * @param tenant
     * @param today
     * @param companyId
     * @param trustNo
     */
    private void processAccountInfoData(TenantEscrowAuthorizationInfoDto tenant, String today, String companyId, String trustNo, int mouth) {
        try {

            //1 获取数据
            Map<String, Object> accountInfoData = cmscGetDataUtil.processAccountInfoData1(tenant, trustNo, cmscUrlPrefix, today, companyId);
            if (PullDataFailureUtil.isFailed(accountInfoData)) {
                pullDataFailureLogService.saveErrorData(tenant.getTenantName(), accountInfoData);
                throw new IllegalArgumentException("获取数据异常");
            }
            log.info("processAccountInfoData 从1001获取 accountInfo" + JSON.toJSONString(accountInfoData));
            //2 封装数据 第十一张表
            List<AccountInfoEntity> entities = getAccountInfoData(tenant, trustNo, accountInfoData);

            //3 保存数据 第十一张表
            accountInfoService.saveData(null, entities);

            List<String> fundCodeList = accountInfoService.getFundCodeList(trustNo, tenant.getTenantName());
            log.info("processAccountInfoData fundCode查询情况为：" + JSON.toJSONString(fundCodeList));
            for (String fundCode : fundCodeList) {
                if (StringUtils.isBlank(fundCode)) {
                    continue;
                }
                Map<String, Object> accountInfoData2 = cmscGetDataUtil.processAccountInfoData2(tenant, trustNo, cmscUrlPrefix, today, companyId, fundCode);
//                Map<String, Object> tgAccountSeqInfoData = cmscGetDataUtil.processTGAccountSeqInfoData(tenant, trustNo, cmscUrlPrefix, today, companyId,fundCode);
                log.info("processAccountInfoData 从1010获取 accountInfo" + JSON.toJSONString(accountInfoData2));
                if (PullDataFailureUtil.isFailed(accountInfoData2)) {
                    String errorJson = JSON.toJSONString(accountInfoData2);
                    if (errorJson.contains("该产品不存在")) {
                        continue;
                    }
                    pullDataFailureLogService.saveErrorData(tenant.getTenantName(), accountInfoData2);
                    log.error("error:processAccountInfoData有异常数据" + errorJson);
                    throw new IllegalArgumentException("获取数据异常");
                }
                //2 封装数据 第十一张表
                List<AccountInfoEntity> entities2 = getAccountInfoData2(tenant, trustNo, accountInfoData2);

                //3 保存数据 第十一张表
                accountInfoService.saveData(null, entities2);

                //2 封装数据 第五张表
                List<TgAccountBalanceInfoEntity> entities1 = getTgAccountBalanceInfoData(tenant, trustNo, accountInfoData2);
                //3 保存数据 第五张表
                tgAccountBalanceInfoService.saveData(null, entities1);
            }
        } catch (Exception e) {
            log.error("processAccountInfoData批量保存fundIno失败！", e);
        }
        // TODO: 2022/1/13 加一个处理失败的日志统计表
    }

    /**
     * 第九张表
     *
     * @param tenant
     * @param today
     * @param companyId
     * @param trustNo
     */
    private void processFundTradeInfoData(TenantEscrowAuthorizationInfoDto tenant, String today, String companyId, String trustNo, int mouth) {
        try {
            String startDate;
            String endDate;
            LocalDate localDate = LocalDate.now();
            LocalDate lastMonth;
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
            endDate = dateTimeFormatter.format(localDate);
            for (int i = 0; i < mouth; i++) {

                lastMonth = localDate.minusMonths(1);

                startDate = dateTimeFormatter.format(lastMonth);
                String finalStartDate = startDate;
                String finalEndDate = endDate;
//                CompletableFuture.supplyAsync(() -> {  //fixme
                try {
                    //1 获取数据
                    Map<String, Object> cmFundTradeInfoDtoMap = cmscGetDataUtil.processFundTradeInfoData(tenant, trustNo, cmscUrlPrefix, today, finalStartDate, finalEndDate, companyId);
                    if (PullDataFailureUtil.isFailed(cmFundTradeInfoDtoMap)) {
                        pullDataFailureLogService.saveErrorData(tenant.getTenantName(), cmFundTradeInfoDtoMap);
//                            return null; //fixme
                        localDate = lastMonth; //fixme
                        endDate = startDate; //fixme
                        continue; //fixme
                    }
                    //2 封装数据
                    List<FundTradeInfoEntity> entities = getFundTradeInfoData(tenant, trustNo, cmFundTradeInfoDtoMap);

                    //3 保存数据
                    fundTradeInfoService.saveData(null, entities);
                } catch (Exception e) {
                    log.error("批量保存FundTradeInfo失败！", e);
                }
                // TODO: 2022/1/13 加一个处理失败的日志统计表
//                    return null; //fixme
//                }, pullDataThreadPool); //fixme
                localDate = lastMonth;
                endDate = startDate;
            }
        } catch (Exception e) {
            log.error("批量保存FundTradeInfo失败！", e);
        }
        // TODO: 2022/1/13 加一个处理失败的日志统计表
    }

    /**
     * 第三张表
     *
     * @param tenant
     * @param trustNo
     * @param today
     */
    private void processFundNetValueInfoData(TenantEscrowAuthorizationInfoDto tenant, String today, String companyId, String trustNo, int mouth) {
        try {
            String startDate;
            String endDate;
            LocalDate localDate = LocalDate.now();
            LocalDate lastMonth;
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
            endDate = dateTimeFormatter.format(localDate);
            for (int i = 0; i < mouth; i++) {

                lastMonth = localDate.minusMonths(1);
                startDate = dateTimeFormatter.format(lastMonth);
                String finalStartDate = startDate;
                String finalEndDate = endDate;
//                CompletableFuture.supplyAsync(() -> {  //fixme
                try {
                    //1 获取数据
                    Map<String, Object> fundValueData = cmscGetDataUtil.processFundNetValueInfoData(tenant, trustNo, cmscUrlPrefix, today, finalStartDate, finalEndDate, companyId);
                    if (PullDataFailureUtil.isFailed(fundValueData)) {
                        pullDataFailureLogService.saveErrorData(tenant.getTenantName(), fundValueData);
//                            return null; //fixme
                        localDate = lastMonth; //fixme
                        endDate = startDate;//fixme
                        continue; //fixme
                    }
                    //2 封装数据 第三张表
                    List<FundNetValueInfoEntity> entities = getFundNetValueInfoData(tenant, trustNo, fundValueData);

                    //3 保存数据 第三张表
                    fundNetValueInfoService.saveData(null, entities);
                } catch (Exception e) {
                    log.error("批量保存fundNetValueInfo失败！", e);
                }
                // TODO: 2022/1/13 加一个处理失败的日志统计表
//                    return null; //fixme
//                }, pullDataThreadPool);  //fixme
                localDate = lastMonth;
                endDate = startDate;
            }
        } catch (Exception e) {
            log.error("批量保存FundNetValueInfo失败！", e);
        }
        // TODO: 2022/1/13 加一个处理失败的日志统计表
    }

    /**
     * 第二张表 & 第十三张表
     *
     * @param tenant
     * @param trustNo
     * @param today
     */
    private void processInvestorInfoData(TenantEscrowAuthorizationInfoDto tenant, String today, String companyId, String trustNo, int mouth) {
        try {

            //1 获取数据
            Map<String, Object> investorInfoData = cmscGetDataUtil.processInvestorInfoData(tenant, trustNo, cmscUrlPrefix, today, companyId);
            if (PullDataFailureUtil.isFailed(investorInfoData)) {
                pullDataFailureLogService.saveErrorData(tenant.getTenantName(), investorInfoData);
                throw new IllegalArgumentException("获取数据异常");
            }
            //2 封装数据 第二张表
            Map<String, Object> map = getInvestorInfoData(tenant, trustNo, investorInfoData);
            List<InvestorInfoEntity> entities = (List<InvestorInfoEntity>) map.get("result");

            //3 保存数据 第二张表
            investorInfoService.saveData(null, entities);

            //1 获取数据
            Map<String, Object> investorBankInfoData = investorInfoData;

            List<InvestorBankInfoEntity> entities1 = (List<InvestorBankInfoEntity>) map.get("result1");

            log.info("processInvestorInfoData" + JSON.toJSONString(investorBankInfoData));

            //2 封装数据 第十三张表
//            List<InvestorBankInfoEntity> entities1 = getInvestorBankInfoData(tenant, trustNo, investorBankInfoData);

            //3 保存数据 第十三张表
            investorBankInfoService.saveData(null, entities1);

        } catch (Exception e) {
            log.error("批量保存fundIno失败！", e);
        }
        // TODO: 2022/1/13 加一个处理失败的日志统计表
    }


    /**
     * 第十一张表(1)
     *
     * @param tenant
     * @param trustNo
     * @param fundValueData
     * @return
     */
    public List<AccountInfoEntity> getAccountInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo, Map<String, Object> fundValueData) {
        List<AccountInfoEntity> result = new ArrayList<>();
        Map<String, String> currencyDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.CURRENCY_SERVICE, trustNo);


        if (!fundValueData.isEmpty()) {
            fundValueData.entrySet().forEach(entry -> {
                //CMMJAccountInfoDto dto = (CMMJAccountInfoDto) entry.getValue();
                CMMJAccountInfoDto dto = JSON.parseObject(JSON.toJSONString(entry.getValue()), CMMJAccountInfoDto.class);
                log.info("account_info_currency原值={},映射值={}", dto.getBz(), MatchDataDictionaryKeyUtil.getKey(currencyDir, dto.getBz()));

                result.add(AccountInfoEntity.builder()
//                        .currency(MatchDataDictionaryKeyUtil.getKey(currencyDir,dto.getBz()))
                        .currency(MatchDataDictionaryKeyUtil.getKey(currencyDir, dto.getBz()))
                        .innerFundCode(dto.getCpdm())
                        .fundCode(dto.getCpdm())
                        .fundName(dto.getCpmc())
                        .branchBankName(dto.getKhzh())
                        .bankAcco(dto.getZhh())
                        .nameInBank(dto.getZhmc())
                        .accoTypeCode("ZJ002")
                        .trustNo(trustNo)
                        .admin(tenant.getTenantName())
                        .createTime(new Date())
                        .updateTime(new Date())
                        .build());
            });
            }

        return result;
    }


    /**
     * 第十一张表(2)
     *
     * @param tenant
     * @param trustNo
     * @param fundValueData
     * @return
     */
    public List<AccountInfoEntity> getAccountInfoData2(TenantEscrowAuthorizationInfoDto tenant, String trustNo, Map<String, Object> fundValueData) {
        List<AccountInfoEntity> result = new ArrayList<>();
        if (!fundValueData.isEmpty()) {

            fundValueData.entrySet().forEach(entry -> {
                //CMTGHAccountInfoDto dto = (CMTGHAccountInfoDto) entry.getValue();
                CMTGHAccountInfoDto dto = JSON.parseObject(JSON.toJSONString(entry.getValue()), CMTGHAccountInfoDto.class);
                result.add(AccountInfoEntity.builder()
                        .fundName(dto.getFundName())
                        .fundCode(dto.getFundCode())
                        .innerFundCode(dto.getFundCode())
                        .bankAcco(dto.getAccountNo())
                        .nameInBank(dto.getAccountName())
                        .branchBankName(dto.getOpenAccountBank())
                        .accoTypeCode("ZJ001")
                        .trustNo(trustNo)
                        .admin(tenant.getTenantName())
                        .createTime(new Date())
                        .updateTime(new Date())
                        .build());
            });
        }
        return result;
    }

    /**
     * 第十一张表(3)
     *
     * @param tenant
     * @param trustNo
     * @param fundValueData
     * @return
     */
    private List<AccountInfoEntity> getAccountInfoData3(TenantEscrowAuthorizationInfoDto tenant, String trustNo, Map<String, Object> fundValueData) {
        List<AccountInfoEntity> result = new ArrayList<>();
        if (!fundValueData.isEmpty()) {

            fundValueData.entrySet().forEach(entry -> {
//                CMTgAccountBalanceInfoDto dto = (CMTgAccountBalanceInfoDto) entry.getValue();
                CMTGHAccountInfoDto dto = JSON.parseObject(JSON.toJSONString(entry.getValue()), CMTGHAccountInfoDto.class);
                result.add(
                        AccountInfoEntity.builder()
                                .fundName(dto.getFundName())
                                .fundCode(dto.getFundCode())
                                .innerFundCode(dto.getFundCode())
                                .bankAcco(dto.getAccountNo())
                                .nameInBank(dto.getAccountName())
                                .branchBankName(dto.getOpenAccountBank())
                                .accoTypeCode("ZJ001")
                                .trustNo(trustNo)
                                .admin(tenant.getTenantName())
                                .createTime(new Date())
                                .updateTime(new Date())
                                .build());
            });
        }

        return result;
    }

    /**
     * 第二张表
     *
     * @param tenant
     * @param trustNo
     * @param fundValueData
     * @return
     */
    public Map<String, Object> getInvestorInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo, Map<String, Object> fundValueData) {
        HashMap<String, Object> stringObjectHashMap = new HashMap<>();
        List<InvestorInfoEntity> result = new ArrayList<>();
        List<InvestorBankInfoEntity> result1 = new ArrayList<>();

        Map<String, String> custTypeCsdcDic = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.CUST_TYPE_CSDC_SERVICE, trustNo);
        Map<String, Map<String, String>> identityTypeCsdcDic = certificateCsdcService.queryCertificateWithDetail(trustNo);

        if (!fundValueData.isEmpty()) {

            fundValueData.entrySet().forEach(entry -> {
                //CMInvestorInfoDto dto = (CMInvestorInfoDto) entry.getValue();
                CMInvestorInfoDto dto = JSON.parseObject(JSON.toJSONString(entry.getValue()), CMInvestorInfoDto.class);
                String custType = MatchDataDictionaryKeyUtil.getKey(custTypeCsdcDic, dto.getCustType());
                String identityType = MatchDataDictionaryKeyUtil.getKey(custType, identityTypeCsdcDic, dto.getCertificateType());
                log.info("investor_info_custType原值={},映射值={}", dto.getCustType(), custType);
                log.info("investor_info_identityType原值={},映射值={}", dto.getCertificateType(), identityType);

                result.add(InvestorInfoEntity.builder()
                        .custName(dto.getCustName())
//                        .custType(custType)
                        .custType(custType)
//                        .identityType(identityType)
                        .identityType(identityType)
                        .identityNo(dto.getCertificateNo())
                        .fundAcco(dto.getTaAccountId())
                        .accoOpenDate(dto.getOpenDate())
                        .individualOrInstitution("是".equals(dto.getIndividualOrInstitution()) ? 1 : 0)
                        .trustNo(trustNo)
                        .admin(tenant.getTenantName())
                        .createTime(new Date())
                        .updateTime(new Date())
                        .build());

                result1.add(InvestorBankInfoEntity.builder()
                        .fundAcco(dto.getTaAccountId())
                        .tradeAcco(dto.getTransactionAccountId())
                        .nameInBank(dto.getAcctName())
                        .bankNo(dto.getAcctNo())
                        .branchBankName(dto.getClearingAgency())
                        .bankProvince(dto.getProvinces())
                        .bankCity(dto.getCity())
                        .bankNoType("银行账号")
                        .trustNo(trustNo)
                        .admin(tenant.getTenantName())
                        .createTime(new Date())
                        .updateTime(new Date())
                        .build());

            });
        }
        stringObjectHashMap.put("result", result);
        stringObjectHashMap.put("result1", result1);

        return stringObjectHashMap;
    }
    /**
     * 第十三张表
     *
     * @param tenant
     * @param trustNo
     * @param fundValueData
     * @return
     */
    public List<InvestorBankInfoEntity> getInvestorBankInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo, Map<String, Object> fundValueData) {
        List<InvestorBankInfoEntity> result = new ArrayList<>();

//        Map<String, String> custTypeCsdcDic = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.CUST_TYPE_CSDC_SERVICE, trustNo);
//        Map<String, Map<String, String>> identityTypeCsdcDic = certificateCsdcService.queryCertificateWithDetail(trustNo);

        if (!fundValueData.isEmpty()) {

            fundValueData.entrySet().forEach(entry -> {
                CMInvestorBankInfoDto dto = (CMInvestorBankInfoDto) entry.getValue();

                result.add(InvestorBankInfoEntity.builder()
                        .fundAcco(dto.getTaAccountId())
                        .tradeAcco(dto.getTransactionAccountId())
                        .nameInBank(dto.getAcctName())
                        .bankNo(dto.getAcctNo())
                        .branchBankName(dto.getClearingAgency())
                        .bankProvince(dto.getProvinces())
                        .bankCity(dto.getCity())
                        .bankNoType("银行账号")
                        .trustNo(trustNo)
                        .admin(tenant.getTenantName())
                        .createTime(new Date())
                        .updateTime(new Date())
                        .build());
            });
        }

        return result;
    }

    /**
     * 第五张表
     *
     * @param tenant
     * @param trustNo
     * @param tgAccountBalanceInfoMap
     * @return
     */
    public List<TgAccountBalanceInfoEntity> getTgAccountBalanceInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo, Map<String, Object> tgAccountBalanceInfoMap) {
        List<TgAccountBalanceInfoEntity> result = new ArrayList<>();


        if (!tgAccountBalanceInfoMap.isEmpty()) {

            tgAccountBalanceInfoMap.entrySet().forEach(entry -> {

                //CMTgAccountBalanceInfoDto dto = (CMTgAccountBalanceInfoDto) entry.getValue();
                CMTgAccountBalanceInfoDto dto = JSON.parseObject(JSON.toJSONString(entry.getValue()), CMTgAccountBalanceInfoDto.class);

                result.add(TgAccountBalanceInfoEntity.builder()
                        .bankAcco(dto.getAccountNo())
                        .accoBalance(BigDecimalUtil.str2BigDecimal(dto.getBalance()))
                        .updateDate(dto.getUpdateTime())
                        .trustNo(trustNo)
                        .admin(tenant.getTenantName())
                        .createTime(new Date())
                        .updateTime(new Date())
                        .build());

            });
        }
        return result;
    }

    /**
     * 第六张表
     *
     * @param tenant
     * @param trustNo
     * @param tgAccountBalanceInfoMap
     * @return
     */
    public List<TgAccountSeqInfoEntity> getTgAccountSeqInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo, Map<String, Object> tgAccountBalanceInfoMap) {
        List<TgAccountSeqInfoEntity> result = new ArrayList<>();

        Map<String, String> paymentDirectionDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.PAYMENT_DIRECTION_SERVICE, trustNo);


        if (!tgAccountBalanceInfoMap.isEmpty()) {

            tgAccountBalanceInfoMap.entrySet().forEach(entry -> {
                //CMTgAccountSeqInfoDto dto = (CMTgAccountSeqInfoDto) entry.getValue();
                CMTgAccountSeqInfoDto dto = JSON.parseObject(JSON.toJSONString(entry.getValue()), CMTgAccountSeqInfoDto.class);

                SimpleDateFormat rq = new SimpleDateFormat("yyyyMMdd");
                SimpleDateFormat sj = new SimpleDateFormat("HH:mm:ss");
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String rqStr = null;
                String sjStr = null;
                try {
                    String tradeDate = dto.getTradeDate();
                    Date parse = simpleDateFormat.parse(tradeDate);
                    rqStr = rq.format(parse);
                    if (rqStr != null && rqStr.length() > 10) {
                        rqStr = rqStr.substring(0, 10);
                    }
                    sjStr = sj.format(parse);
                } catch (Exception e) {
                    log.error(dto.getTradeDate() + "日期转换异常", e);
                }
                log.info("tg_account_seq_info_transferInOut原值={},映射值={}", dto.getReceiptDirection(), MatchDataDictionaryKeyUtil.getKey(paymentDirectionDir, dto.getReceiptDirection()));
                log.info("tg_account_seq_info_transferDate={},transferTime={}", rqStr, sjStr);

                result.add(TgAccountSeqInfoEntity.builder()
                        .innerFundCode(dto.getFundCode())
                        .fundName(dto.getFundName())
                        .fundCode(dto.getFundCode())
                        .account(dto.getOwnAccount())
                        .transferDate(rqStr)
                        .transferTime(sjStr)
//                                .transferInOut(MatchDataDictionaryKeyUtil.getKey(paymentDirectionDir, dto.getReceiptDirection()))
                        .transferInOut(MatchDataDictionaryKeyUtil.getKey(paymentDirectionDir, dto.getReceiptDirection()))
                        .amount(BigDecimalUtil.str2BigDecimal(dto.getTradingAmount()))
                        .opAccountName(dto.getCounterpartyName())
                        .opAccount(dto.getCounterpartyAccount())
                        .opBankName(dto.getCounterpartyOpenAccountBank())
                        .summary(dto.getBankAbstract())
                        .memo(dto.getPostScript())
                        .trustNo(trustNo)
                        .admin(tenant.getTenantName())
                        .createTime(new Date())
                        .updateTime(new Date())
                        .build());
            });
        }
        return result;
    }

    public static final Pattern letterPattern = Pattern.compile("^[a-zA-Z]$");

    /**
     * 第一张表转化
     *
     * @param tenant
     * @param trustNo
     * @param map
     * @return
     */
    public List<FundInfoEntity> getFundInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo, Map<String, Object> map, String cmscUrlPrefix, String today, String companyId) {
        List<FundInfoEntity> result = new ArrayList<>();

        if (!map.isEmpty()) {
            map.entrySet().forEach(entry -> {
                //CMPrdInfoDto dto = (CMPrdInfoDto) entry.getValue();
                CMPrdInfoDto dto = JSON.parseObject(JSON.toJSONString(entry.getValue()), CMPrdInfoDto.class);
                //调用1004查询持仓信息接口，获取产品状态（运行、清盘）
                //林园、凌顶在中转才能调用招商接口，这里跳过
                boolean fundStatus = true;
                List<String> transferDeployAdminList = Arrays.asList("P1002894", "P1067183");
                if (!transferDeployAdminList.contains(tenant.getTenantName())){
                    fundStatus = cmscGetDataUtil.getFundStatus(tenant, trustNo, cmscUrlPrefix, today, companyId, dto.getFundCode());
                }
                log.info("fund_info持仓查询入参={},得到产品状态={}", dto.getFundCode(), fundStatus);
                String fundCode = dto.getFundCode();

                String fundName = dto.getFundName();
                if (StringUtils.isBlank(fundName)) {
                    fundName = "null";
                }

                //设置fundCode
                log.info("getFundInfoData：上游拿到的fundCode={},fundName={}", fundCode, fundName);
                String fundInfoFundCode = "";
                if (StringUtils.isBlank(fundName)) {
                    log.error("当前1009接口上线数据为{},fundName为blank:{}", JSON.toJSONString(dto), fundName);
                } else {
                    String substring = fundName.substring(fundName.length() - 1);

                    Matcher matcher = letterPattern.matcher(substring);
                    boolean lastCharIsLetter = matcher.find();

                    if (lastCharIsLetter) {
                        String fundNamePrefix = fundName.substring(0, fundName.length() - 1);
                        log.info("fundName为：{}末尾为字母，去掉字母后为{}去数据库查", fundName, fundNamePrefix);
                        fundInfoFundCode = getFundCodeByFundName(fundNamePrefix, tenant);
                        log.info("查询数据库、上游、字典表拿到的fundCode为{}", fundInfoFundCode);
                    } else {
                        fundInfoFundCode = fundCode;
                    }
                }

                log.info("getFundInfoData:入参fundCode{},入参fundName{},出参fundInfoFundCode{}", fundCode, fundName, fundInfoFundCode);
                result.add(FundInfoEntity.builder()
                        .fundCode(fundInfoFundCode)
                        .innerFundCode(fundCode)
                        .fundName(dto.getFundName())
                        .fundStatus(fundStatus ? "1" : "3")
                        .admin(tenant.getTenantName())
                        .trustNo(trustNo)
                        .createTime(new Date())
                        .updateTime(new Date())
                        .build());
            });
        }
        return result;
    }

    private String getFundCodeByFundName(String fundName, TenantEscrowAuthorizationInfoDto tenant) {
        //1先从数据库查，应该可能已经落过一些数据了
        String fundCode = fundInfoService.getFundCodeByFundName(fundName, tenant.getTrustNo(), tenant.getTenantName());
        if (StringUtils.isNotBlank(fundCode)) {
            return fundCode;
        }

        //查询字典表
        return dataDictionaryZxFndBasicInfoCyService.getFundCodeByFundname(fundName);
    }


    @Override
    public R updateDataDaily(List<TenantEscrowAuthorizationInfoDto> tenants) {
        for (TenantEscrowAuthorizationInfoDto tenant : tenants) {
            if ("25".equals(tenant.getTrustNo())) {
                getDataFromCMSCWithoutTgMj(tenant, 1);
                return R.ok("招商更新完毕");
            }
        }
        log.error("没有租户，updateDataDaily未更新招商!");
        return null;

    }

    @Override
    public R updateSingleDataDaily(TenantEscrowAuthorizationInfoDto tenant) {
        if (!Objects.isNull(tenant)) {
            getDataFromCMSCWithoutTgMj(tenant, 1);
        }
        return null;
    }

    @Override
    public R PullRemoteDataFirstQueueJob() {
        return null;
    }

    @Override
    public R initLaterTenantData(String versionStr, List<TenantEscrowAuthorizationInfoDto> tenants) {
        return null;
    }

    @Override
    public R initLaterSingleTenantData(String versionStr, TenantEscrowAuthorizationInfoDto tenant) {
        log.info("initLaterSingleTenantData is begin...the versionStr is {} ,the tenant is {}", versionStr, JSON.toJSONString(tenant));
        String trustNo = tenant.getTrustNo();
        Integer loopNum = CustodyContants.INIT_BY_MONTH_LOOP_TIME;
        try {
            switch (versionStr) {
                case CustodyContants.R_PT_S_CUSTODY_3_2_6:
                    String today = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
                    String companyId = tenant.getCompanyId();
                    String timeStramp = today;
                    //8  募集户流水表（MJAccount_seq_info） 1002
                    processMJAccountSeqInfoData(tenant, today, companyId, trustNo, loopNum);
                    log.info("管理人{}招商募集户流水更新完成!", tenant.getTenantName());
                    processTGAccountSeqInfoData2(tenant, today, companyId, trustNo, loopNum); //入参需要fundCode 历史
                    log.info("管理人{}招商托管户流水更新完成!", tenant.getTenantName());
                    break;
            }
        }catch (Exception e){
            log.error("招商流水更新失败!", e);
        }
        return null;
    }

    @Override
    public R initByAppointedTrustNoAndMouth(TenantEscrowAuthorizationInfoDto tenant, int mouth) {
        log.info("initByAppointedTrustNoAndMouth_tenant={},mouth={}", JSON.toJSONString(tenant), mouth);

        getDataFromCMSC(tenant, mouth);
        return R.ok();
    }

    private void initTenantDataBy305Patch02(TenantEscrowAuthorizationInfoDto tenant, String trustNo, int loopNum) {
        String today = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        String companyId = tenant.getCompanyId();
        log.info("318patch01版本更新开始");
        processFundInfoData(tenant, today, companyId, trustNo, loopNum);
        log.info("318patch01版本更新开始");

        log.info("邮件更新估值表开始");
        cmscContentsOfValuationSheetByEmail(tenant, trustNo, 12);
        log.info("邮件更新估值表结束");

    }

    @Override
    public R updateData20min(List<TenantEscrowAuthorizationInfoDto> data) {
        return null;
    }

    @Override
    public R updateSingleData20min(TenantEscrowAuthorizationInfoDto tenant) {
        log.info("招商每半小时更新：托管募集信息开始");

        String today = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
//        String companyId = "b759a8a2afef4a2788c5050b4ac6d9f6";
        String companyId = tenant.getCompanyId();
        String timeStramp = today;
        String trustNo = tenant.getTrustNo();
        System.out.println("timeStramp---->--->-->->" + timeStramp);

        //8  募集户流水表（MJAccount_seq_info） 1002
        processMJAccountSeqInfoData(tenant, today, companyId, trustNo, 1);
        log.info("招商每半小时更新:1/4");

        //5  托管户银行账户余额信息表 (TGAccount_balance_info) 1010
        processTGAccountBalanceInfoData(tenant, today, companyId, trustNo, 1); //入参需要fundCode
        log.info("招商每半小时更新:2/4");

        //6  托管户流水表 (TGAccount_seq_info)  1011
        processTGAccountSeqInfoData(tenant, today, companyId, trustNo, 1); //入参需要fundCode 单日
        log.info("招商每半小时更新:3/4");

        //7  募集户银行账户余额信息表 (MJAccount_balance_info)  1001
        processMJAccountBalanceInfoData(tenant, today, companyId, trustNo, 1);
        log.info("招商每半小时更新:4/4");
        return null;
    }

    @Override
    public R updateData1h(List<TenantEscrowAuthorizationInfoDto> data) {
        return null;
    }

    @Override
    public R updateSingleData1h(TenantEscrowAuthorizationInfoDto tenant) {
        return null;
    }

    @Override
    public R updateDataCJ(String date, String flag, TenantEscrowAuthorizationInfoDto tenant) {
        return null;
    }

    @Override
    public R updateNetValueData(List<TenantEscrowAuthorizationInfoDto> tenants) {
        return null;
    }

    @Override
    public R updateSingleNetValueData(TenantEscrowAuthorizationInfoDto tenant) {
        log.info("招商每8点、12点、20点更新数据开始！");
        try {
            String today = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
            String companyId = tenant.getCompanyId();
            String timeStramp = today;
            String trustNo = tenant.getTrustNo();
            int loopTime = CustodyContants.UPDATE_BY_MONTH_DAILY_LOOP_TIME;
            //净值表
            processFundNetValueInfoData(tenant, today, companyId, trustNo, loopTime);
        } catch (Exception e) {
            log.error("招商每8点、12点、20点更新数据异常！", e);
        }
        return R.ok("招商每8点、12点、20点更新数据完成！");
    }

    @Override
    public DubboResult updateMJBalanceData(TenantEscrowAuthorizationInfoDto tenant) {
        try {
            String today = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
            String companyId = tenant.getCompanyId();
            String trustNo = tenant.getTrustNo();
            processMJAccountBalanceInfoData(tenant, today, companyId, trustNo, 1);

            return DubboResult.newSuccess();
        } catch (Exception e) {
            log.error("手动更新募集户余额失败", e);
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "手动更新募集户余额失败" + e.getMessage());
        }
    }

    @Override
    public DubboResult updateMJSeqData(TenantEscrowAuthorizationInfoDto tenant) {
        try {
            String today = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
            String companyId = tenant.getCompanyId();
            String trustNo = tenant.getTrustNo();
            processMJAccountSeqInfoData(tenant, today, companyId, trustNo, 1);

            return DubboResult.newSuccess();
        } catch (Exception e) {
            log.error("手动更新募集户流水失败", e);
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "手动更新募集户流水失败" + e.getMessage());
        }
    }

    @Override
    public DubboResult updateTGBalanceData(TenantEscrowAuthorizationInfoDto tenant) {
        try {
            String today = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
            String companyId = tenant.getCompanyId();
            String trustNo = tenant.getTrustNo();
            processTGAccountBalanceInfoData(tenant, today, companyId, trustNo, 1);

            return DubboResult.newSuccess();
        } catch (Exception e) {
            log.error("手动更新托管户余额失败", e);
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "手动更新托管户余额失败" + e.getMessage());
        }
    }

    @Override
    public DubboResult updateTGSeqData(TenantEscrowAuthorizationInfoDto tenant) {
        try {
            String today = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
            String companyId = tenant.getCompanyId();
            String trustNo = tenant.getTrustNo();
            processTGAccountSeqInfoData(tenant, today, companyId, trustNo, 1);

            return DubboResult.newSuccess();
        } catch (Exception e) {
            log.error("手动更新托管户流水失败", e);
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "手动更新托管户流水失败" + e.getMessage());
        }
    }

    @Autowired
    private TenantEmailAuthorizationInfoServiceImpl tenantEmailInfoService;

    @Autowired
    MailNewUtils mailNewUtils;

    @Autowired
    public Environment environment;
    public static final String[] OFFICIAL_PROFILES = {"prod", "ty-prod"};

    //招商-邮件获取估值表内容
    private void cmscContentsOfValuationSheetByEmail(TenantEscrowAuthorizationInfoDto tenant, String trustNo, int loopNum) {
        log.info("cmscContentsOfValuationSheetByEmail入参tenant={},trustNo={},loopNum={}", tenant, trustNo, loopNum);
        List<TenantEmailAuthorizationInfoEntity> tenantEmailAuthorizationInfoEntities = tenantEmailInfoService.queryByTenantName(tenant.getTenantName(), trustNo);
        for (TenantEmailAuthorizationInfoEntity tenantEmail : tenantEmailAuthorizationInfoEntities) {
            String purpose = EmailConfigPurposeEnum.ALL.getPurpose();
            log.info("cmscContentsOfValuationSheetByEmail:ALL.getPurpose={},tenantEmail.getPurpose={}", purpose, tenantEmail.getPurpose());
            if (purpose.equals(tenantEmail.getPurpose())) {
                log.info("cmscContentsOfValuationSheetByEmail 邮件配置为all,跳过");
                continue;
            }
            if (!ObjectUtils.isEmpty(tenantEmail)) {
                try {
                    //获取邮件
                    LocalDate localDate = LocalDate.now();
                    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
                    String startTime = dateTimeFormatter.format(localDate.minusMonths(loopNum));
                    //拿到所有邮件
                    //Message[] weMessage = MailUtil.getWEMessage(tenantEmail.getEmailHost(), tenantEmail.getEmailAddress(), tenantEmail.getEmailSecret(), ZhongXinConstants.PROTOCOL);
                    Message[] weMessage = MailUtil.getMessageByTenantEmail(tenantEmail);
                    //mailNewUtils.printMessageInfo(weMessage,500);
                    //过滤符合条件的邮件
                    List<Message> messages = MailUtil.filterMessage(weMessage,
                            tenantEmail.getFromEmail(),
                            startTime,
                            tenantEmail.getEmailSubject(),
                            Boolean.TRUE);
                    //打印邮件相关信息 并且更新
                    if (!CollectionUtils.isEmpty(messages)) {
                        log.info("cmscContentsOfValuationSheetByEmail_拿到的messages数量为{}", messages.size());
                        //生产且没有配置附件路径 就不保存
                        Profiles profiles = Profiles.of(OFFICIAL_PROFILES);
                        boolean isOfficial = environment.acceptsProfiles(profiles);
                        String dirFilePath = tenantEmail.getDirFilePath();
                        if (StringUtils.isBlank(dirFilePath) && isOfficial) {
                            log.info("生产环境且没有配置路径，不保存附件！");
                        } else {
                            if (StringUtils.isBlank(dirFilePath)) {
                                dirFilePath = mailNewUtils.getDefaultAttachmentParentPath(tenantEmail);
                            }
                        }
                        if (StringUtils.isNotBlank(dirFilePath)) {
                            for (Message message : messages) {
                                //邮件保存路径
                                mailNewUtils.saveAttachment(message, dirFilePath);
                                // todo 处理邮件
                                MailUtil re = new MailUtil((MimeMessage) message);
                            }
                        }
                        int i = 0;
                        for (Message message : messages) {
                            i++;
                            log.info("处理第{}封邮件", i);
                            MailUtil re = new MailUtil((MimeMessage) message);
                            handleCmscEmailMessage(message, tenant, re.getSubject());
                        }
                    } else {
                        log.error("招商cmscContentsOfValuationSheetByEmail 过滤后messages信息为空");
                    }
                } catch (ParseException pe) {
                    pe.printStackTrace();
                    log.error("时间转化异常！", pe);
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                    log.error("分析邮件异常！", ioe);
                } catch (MessagingException me) {
                    me.printStackTrace();
                    log.error("获取邮件异常！", me);
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error("！", e);
                }
            }
        }
    }

    public static final String NET_VALUE_TABLE = "估值表";

    public static final String START_ROW_FLAG = "科目代码";

    public static final String TOTAL_ASSERT_ROW = "资产类合计";

    //不含中文
    public static final Pattern pattern = Pattern.compile("[^\\u4e00-\\u9fa5]+");

    public static final String DEFAULT_PATTERN = "yyyyMMdd";
    public static final Pattern patternFundCode = Pattern.compile("^[A-Za-z0-9]+");
    public static final Pattern patternFundname = Pattern.compile("[\\u4e00-\\u9fa5]+[0-9]+[\\u4e00-\\u9fa5]+[0-9]+");

    /**
     * 更新totalAsset
     *
     * @param part
     * @throws MessagingException
     * @throws IOException
     */
    public void handleEmailMessage(Part part, TenantEscrowAuthorizationInfoDto tenant, String subject) throws MessagingException, IOException, ParseException {
        String fileName;
        if (part.isMimeType("multipart/*")) {
            Multipart mp = (Multipart) part.getContent();
            BodyPart mPart;
            for (int i = 0; i < mp.getCount(); i++) {
                try {
                    mPart = mp.getBodyPart(i);
                    fileName = mPart.getFileName();
                    //
                    if ((fileName != null)) {
                        fileName = MailUtil.decodeText(fileName);
                        log.info("temp:subject={}", subject);
                        String date = StrUtil.getDateStrFromStringByPattern(subject, MailUtil.DATE_PATTERN);
                        log.info("fileName:{}", fileName);
                        //fundCode

                        Matcher matcherFundCode = patternFundCode.matcher(fileName);
                        String fundCode = "";
                        if (matcherFundCode.find()) {
                            fundCode = matcherFundCode.group();
                        }

                        log.info("fundCode:{}", fundCode);
                        //valueDate
                        String valueDate = StrUtil.getDateStrFromStringByPattern(fileName, MailUtil.DATE_PATTERN);
                        log.info("valueDate:{}", valueDate);
                        //fundName
                        Matcher matcherFundname = patternFundname.matcher(fileName);
                        String group = "";
                        if (matcherFundname.find()) {
                            group = matcherFundname.group();
                        }

                        String fundName = group.split("基金")[0] + "基金";
                        log.info("fundName:{}", fundName);
                        Workbook workbook = ExcelWriteUtil.getWorkbook(mPart.getInputStream());
                        Sheet sheetAt = workbook.getSheetAt(0);
                        boolean flag = false;
                        int rowNum = 0;
                        List<FundValueTableDataInfoEntity> entities = new ArrayList<>();
                        List<FundValuationEntity> fundValuationEntityList = new ArrayList<>();
                        for (Row row : sheetAt) {
                            rowNum++;
                            try {
                                if (Objects.isNull(row) || Objects.isNull(row.getCell(0))) {
                                    flag = false;
                                    continue;
                                }
                                if (row.getCell(0).getCellTypeEnum().equals(CellType.STRING) && START_ROW_FLAG.equals(ExcelUtils.getStringValue(row.getCell(0)))) {
                                    flag = true;
                                    continue;
                                }

                                //更新数据 fundValueDataInfo
                                if (flag) {
                                    String cellx0 = ExcelUtils.getStringValue(row.getCell(0));
                                    boolean matches = pattern.matcher(cellx0).matches();
                                    if (!matches) {
                                        log.info("该行第一个单元格内容为{},含有中文，跳过查询下一行", cellx0);
                                        flag = false;
                                        continue;
                                    }

                                    if (StringUtils.isBlank(cellx0)) {
                                        log.info("该行第一个单元格内容为空,含有中文，跳过查询下一行", cellx0);
                                        flag = false;
                                        continue;
                                    }

                                    char keyChar = 'a';
                                    HashMap<Character, String> dataMap = new HashMap<>();
                                    for (int j = 0; j < 13; j++) {
                                        Cell cell = row.getCell(j);
                                        String stringValue = ExcelUtils.getStringValue(cell);
                                        dataMap.put(keyChar, stringValue);
                                        keyChar++;
                                    }
                                    log.info("招商估值表邮件解析第{}行，拿到的内容{}", rowNum, JSON.toJSONString(dataMap));
                                    Map<String, String> currencyDic = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.CURRENCY_SERVICE, tenant.getTrustNo());//币种
                                    String currency = MatchDataDictionaryKeyUtil.getKey(currencyDic, dataMap.get('c'));

                                    FundValueTableDataInfoEntity build = FundValueTableDataInfoEntity.builder()
                                            .fundCode(fundCode)
                                            .fundName(fundName)
                                            .valueDate(valueDate)
                                            .kmCode(StringUtils.isBlank(dataMap.get('a')) ? null : dataMap.get('a'))
                                            .kmName(StringUtils.isBlank(dataMap.get('b')) ? null : dataMap.get('b'))
                                            .currency(currency)  //  c列
                                            .vaRate(StringUtils.isBlank(dataMap.get('d')) ? null : new BigDecimal(dataMap.get('d')))  // d列
                                            .amount(StringUtils.isBlank(dataMap.get('e')) ? null : new BigDecimal(dataMap.get('e')))  // e列
                                            .perCost(StringUtils.isBlank(dataMap.get('f')) ? null : new BigDecimal(dataMap.get('f')))  // f列
                                            .portCost(StringUtils.isBlank(dataMap.get('g')) ? null : new BigDecimal(dataMap.get('g')))  // g列
                                            .costBi(StringUtils.isBlank(dataMap.get('h')) ? null : new BigDecimal(dataMap.get('h')))  // h列
                                            .vapPrice(StringUtils.isBlank(dataMap.get('i')) ? null : new BigDecimal(dataMap.get('i')))  // i列
                                            .portMv(StringUtils.isBlank(dataMap.get('j')) ? null : new BigDecimal(dataMap.get('j')))  // j列
                                            .mvBl(StringUtils.isBlank(dataMap.get('k')) ? null : new BigDecimal(dataMap.get('k')))  // k列
                                            .portIv(StringUtils.isBlank(dataMap.get('l')) ? null : new BigDecimal(dataMap.get('l')))  //l列
                                            .suspension(StringUtils.isBlank(dataMap.get('m')) ? null : dataMap.get('m'))  //m列
                                            .trustNo("25")
                                            .admin(tenant.getTenantName())
                                            .updateTime(new Date())
                                            .build();

                                    log.info("拿到的fundValueTableDataInfoEntity为{}", JSON.toJSONString(build));
                                    entities.add(build);
                                    //估值表数据字典
                                    Map<String, String> typeOfFundValuationDic = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.TYPE_OF_FUND_VALUATION, tenant.getTrustNo());//币种
                                    Map<String, String> keyValue = typeOfFundValuationService.queryKeyValue();
                                    String kmCode = MatchDataDictionaryKeyUtil.getKey(typeOfFundValuationDic, dataMap.get('a'));
                                    String kmName = MatchDataDictionaryKeyUtil.getKey(keyValue, kmCode);
                                    if (StringUtils.isNotBlank(kmCode)) {
                                        FundValuationEntity fundValuationEntity = FundValuationEntity.builder()
                                                .fundCode(fundCode)
                                                .fundName(fundName)
                                                .valueDate(valueDate)
                                                .kmCode(kmCode)
                                                .kmName(kmName)
                                                .currency(currency)  //  c列
                                                .vaRate(StringUtils.isBlank(dataMap.get('d')) ? null : new BigDecimal(dataMap.get('d')))  // d列
                                                .amount(StringUtils.isBlank(dataMap.get('e')) ? null : new BigDecimal(dataMap.get('e')))  // e列
                                                .perCost(StringUtils.isBlank(dataMap.get('f')) ? null : new BigDecimal(dataMap.get('f')))  // f列
                                                .portCost(StringUtils.isBlank(dataMap.get('g')) ? null : new BigDecimal(dataMap.get('g')))  // g列
                                                .costBi(StringUtils.isBlank(dataMap.get('h')) ? null : new BigDecimal(dataMap.get('h')))  // h列
                                                .vapPrice(StringUtils.isBlank(dataMap.get('i')) ? null : new BigDecimal(dataMap.get('i')))  // i列
                                                .portMv(StringUtils.isBlank(dataMap.get('j')) ? null : new BigDecimal(dataMap.get('j')))  // j列
                                                .mvBl(StringUtils.isBlank(dataMap.get('k')) ? null : new BigDecimal(dataMap.get('k')))  // k列
                                                .portIv(StringUtils.isBlank(dataMap.get('l')) ? null : new BigDecimal(dataMap.get('l')))  //l列
                                                .suspension(StringUtils.isBlank(dataMap.get('m')) ? null : dataMap.get('m'))  //m列
                                                .trustNo("25")
                                                .admin(tenant.getTenantName())
                                                .updateTime(new Date())
                                                .build();

                                        fundValuationEntityList.add(fundValuationEntity);
                                    }
                                }
                            } catch (Exception e) {
                                log.error("招商估值表邮件解析第{}行异常,尝试解析下一行", rowNum, e);
                                continue;
                            }
                        }
                        if (!CollectionUtils.isEmpty(entities)) {
                            log.info("从subject:{}中获取fundValueTableData 共计{}条", subject, entities.size());
                            fundValueTableDataInfoService.saveData(null, entities);
                        } else {
                            log.error("从subject:{}中未获得fundValueTableData", subject);
                        }
                    }
                }catch (Exception e){
                    log.error("handleEmailMessage 异常：{}",e);
                }

            }
        }
    }

    public void handleCmscEmailMessage(Part part, TenantEscrowAuthorizationInfoDto tenant, String subject) throws MessagingException, IOException, ParseException {
        log.info("处理邮件 handleCmscEmailMessage tenant={} subject={}, trustNo={}",JSON.toJSONString(tenant),subject);
        String fileName;
        Map<String, String> currencyDic = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.CURRENCY_SERVICE, tenant.getTrustNo());
        Map<String, String> typeOfFundValuation = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.TYPE_OF_FUND_VALUATION, tenant.getTrustNo());
        Map<String, String> fundValuationMap = typeOfFundValuationService.queryKeyValue();

        if (part.isMimeType("multipart/*")) {
            Multipart mp = (Multipart) part.getContent();
            BodyPart mPart;
            for (int i = 0; i < mp.getCount(); i++) {
                try{
                    mPart = mp.getBodyPart(i);
                    fileName = mPart.getFileName();
                    if ((fileName != null)) {
                        fileName = MailUtil.decodeText(fileName);
                        HSSFWorkbook hssfWorkbook = new HSSFWorkbook(mPart.getInputStream());
                        HSSFSheet sheet = hssfWorkbook.getSheetAt(0);
                        CmscEmailDTO cmscEmailDTO = parseExcelCmsc(sheet, fileName, currencyDic, typeOfFundValuation, fundValuationMap);
                        log.error("cmscEmailDTO:{}",cmscEmailDTO);

                        //更新估值表
                        List<FundValueTableDataInfoEntity> fundValueTableDataInfoList = cmscEmailDTO.getFundValueTableDataInfoEntity();

                        if (!CollectionUtils.isEmpty(fundValueTableDataInfoList)){
                            for (FundValueTableDataInfoEntity entity: fundValueTableDataInfoList
                            ) {
                                entity.setAdmin(tenant.getTenantName());
                                entity.setTrustNo(tenant.getTrustNo());
                                entity.setCreateTime(new Date());
                                entity.setUpdateTime(new Date());
                            }
                        }
                        fundValueTableDataInfoService.saveData(null,fundValueTableDataInfoList);

                        // fundValuation
                        List<FundValuationEntity> fundValuationEntityList = cmscEmailDTO.getFundValuationEntityList();
                        if (!CollectionUtils.isEmpty(fundValuationEntityList)){
                            for (FundValuationEntity entity: fundValuationEntityList
                            ) {
                                entity.setAdmin(tenant.getTenantName());
                                entity.setTrustNo(tenant.getTrustNo());
                                entity.setCreateTime(new Date());
                                entity.setUpdateTime(new Date());
                            }
                        }
                        fundValuationService.saveData(null, fundValuationEntityList);
                    }
                }catch (Exception e){
                    e.printStackTrace();
                    log.error("招商处理估值表邮件失败!", e);
                }
            }
        }
    }

    public CmscEmailDTO parseExcelCmsc(HSSFSheet sheet, String fileName, Map<String, String> currencyDic, Map<String, String> typeOfFundValuation, Map<String, String> fundValuationMap) {
        String fundName = null;
        String fundCode = null;
        String fundValueDate = null;
        CmscEmailDTO result = new CmscEmailDTO();
        int LAST_ROW_OF_SUBJECT_CODE = outsourceZhongXinService.getLastRowOfSubjectCode(sheet);
        List<FundValueTableDataInfoEntity> fundValueTableDataInfoEntityList = new ArrayList<>();
        List<FundValuationEntity> fundValuationEntityList = new ArrayList<>();
        Pattern yyyyMMddPattern = Pattern.compile(YEAR_MONTH_DAY_REGEX);


        for (int rowNum=0; rowNum <=sheet.getLastRowNum(); rowNum++){
            HSSFRow sheetRow = sheet.getRow(rowNum);
            if (sheetRow == null){
                continue;
            }
            for (int cellNum = 0; cellNum <= sheetRow.getLastCellNum(); cellNum++) {
                HSSFCell cell = sheetRow.getCell(cellNum);
                if (cell == null){
                    continue;
                }
                if (cell.getRowIndex() == 0 && cell.getColumnIndex() ==0){
                    String fundCodeTitle = OutsourceZhongXinService.getValue(cell);
                    Matcher matcher = yyyyMMddPattern.matcher(fundCodeTitle);
                    if (matcher.find()) {
                        fundValueDate = matcher.group();
                    } else {
                        log.error("招商上游excel格式变化fundValueDate无法解析，fundValueDate:{}", fileName);

                    }
                    Matcher matcherFundCode = patternFundCode.matcher(fundCodeTitle);
                    if (matcherFundCode.find()) {
                        fundCode = matcherFundCode.group();
                    } else {
                        log.error("招商上游excel格式变化fundCode无法解析，fileName:{}", fundCodeTitle);
                    }
                    Matcher matcherFundname = patternFundname.matcher(fundCodeTitle);
                    if (matcherFundname.find()) {
                        String group = matcherFundname.group();
                        if (StringUtils.isNotBlank(group)){
                            fundName = group.split("基金")[0] + "基金";
                        }else {
                            log.error("招商上游excel格式变化fundName无法解析，fileName:{}", fileName);
                        }
                    }
                }
                //解析估值表数据 获取A列非中文字段
                if (cell.getColumnIndex() == 0
                        && !CellType.BLANK.equals(cell.getCellTypeEnum())
                        && !"".equals(OutsourceZhongXinService.getValue(cell))
                        && cell.getRowIndex() > LAST_ROW_OF_SUBJECT_CODE) {
                    String kmCode = OutsourceZhongXinService.getValue(cell);
                    String kmName = sheetRow.getCell(1) != null ? OutsourceZhongXinService.getValue(sheetRow.getCell(1)) : null;
                    String currency = sheetRow.getCell(2) != null ? OutsourceZhongXinService.getValue(sheetRow.getCell(2)) : null;
                    BigDecimal vaRate = OutsourceZhongXinService.getBigDecimalFromCell(ExcelUtils.getStringValue(sheetRow.getCell(3)));
                    BigDecimal amount = OutsourceZhongXinService.getBigDecimalFromCell(ExcelUtils.getStringValue(sheetRow.getCell(4)));
                    BigDecimal perCost = OutsourceZhongXinService.getBigDecimalFromCell(ExcelUtils.getStringValue(sheetRow.getCell(5)));
                    BigDecimal portCost = OutsourceZhongXinService.getBigDecimalFromCell(ExcelUtils.getStringValue(sheetRow.getCell(6)));
                    BigDecimal costBi = OutsourceZhongXinService.getBigDecimalFromCell(ExcelUtils.getStringValue(sheetRow.getCell(7)));
                    BigDecimal vapPrice = OutsourceZhongXinService.getBigDecimalFromCell(ExcelUtils.getStringValue(sheetRow.getCell(8)));
                    BigDecimal portMv = OutsourceZhongXinService.getBigDecimalFromCell(ExcelUtils.getStringValue(sheetRow.getCell(9)));
                    BigDecimal mvBl = OutsourceZhongXinService.getBigDecimalFromCell(ExcelUtils.getStringValue(sheetRow.getCell(10)));
                    BigDecimal portIv = OutsourceZhongXinService.getBigDecimalFromCell(ExcelUtils.getStringValue(sheetRow.getCell(11)));
                    String suspension = sheetRow.getCell(12) != null ? OutsourceZhongXinService.getValue(sheetRow.getCell(12)) : null;
                    //币种
                    String targetCurrency = MatchDataDictionaryKeyUtil.getKey(currencyDic, currency);
                    FundValueTableDataInfoEntity entity = FundValueTableDataInfoEntity.builder()
                            .fundCode(fundCode)
                            .fundName(fundName)
                            .valueDate(fundValueDate)
                            .kmCode(kmCode)
                            .kmName(kmName)
                            .currency(targetCurrency)
                            .vaRate(vaRate)
                            .amount(amount)
                            .perCost(perCost)
                            .portCost(portCost)
                            .costBi(costBi)
                            .vapPrice(vapPrice)
                            .portMv(portMv)
                            .mvBl(mvBl)
                            .portIv(portIv)
                            .suspension(suspension)
                            .build();
                    fundValueTableDataInfoEntityList.add(entity);
                    // 新增估值表
                    //获取估值表kmCode估值表
                    String targetKmCode = MatchDataDictionaryKeyUtil.getKey(typeOfFundValuation, kmCode);
                    String targetKmName = fundValuationMap.get(targetKmCode);
                    if (StringUtils.isNotBlank(targetKmCode)) {
                        FundValuationEntity fundValuationEntity = FundValuationEntity.builder()
                                .fundCode(fundCode)
                                .fundName(fundName)
                                .valueDate(fundValueDate)
                                .kmCode(targetKmCode)
                                .kmName(targetKmName)
                                .currency(targetCurrency)
                                .amount(amount)
                                .perCost(perCost)
                                .portCost(portCost)
                                .costBi(costBi)
                                .vapPrice(vapPrice)
                                .portMv(portMv)
                                .mvBl(mvBl)
                                .portIv(portIv)
                                .suspension(suspension)
                                .build();
                        fundValuationEntityList.add(fundValuationEntity);
                    }
                }
            }

        }
        result.setFundValueTableDataInfoEntity(fundValueTableDataInfoEntityList);
        result.setFundValuationEntityList(fundValuationEntityList);
        return result;
    }
}
