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

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.friday.base.common.response.DubboResult;
import com.friday.custody.entity.*;
import com.friday.custody.service.basicService.impl.*;
import com.friday.custody.service.trustService.csc.commom.CSCConstants;
import com.friday.custody.service.trustService.csc.commom.UrlConstant;
import com.friday.custody.service.trustService.csc.utils.SM4Util;
import com.friday.custody.service.trustService.csc.utils.TestHttpUtil;
import com.friday.custody.service.trustService.gtja.utils.NumberUtil;
import com.friday.custody.common.CustodyContants;
import com.friday.custody.dto.CscAppSecretDTO;
import com.friday.custody.dto.TenantEscrowAuthorizationInfoDto;
import com.friday.custody.enums.DataDictionaryTypeEnum;
import com.friday.custody.service.basicService.DataDictionaryTypeCertificateCsdcService;
import com.friday.custody.service.basicService.InvokeRecordService;
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.csc.utils.JsonUtil;
import com.friday.custody.utils.BigDecimalUtil;
import com.friday.custody.utils.MatchDataDictionaryKeyUtil;
import com.friday.custody.utils.R;
import com.friday.custody.utils.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Service
@Slf4j
public class OutSourceCSCServiceImpl implements OutsourceService {
    @Autowired
    private InvokeRecordService invokeRecordService;
    @Autowired
    private PullDataFailureLogService pullDataFailureLogService;
    @Autowired
    private DataDictionaryBasicService dataDictionaryBasicService;
    @Autowired
    private DataDictionaryTypeCertificateCsdcService certificateCsdcService;
    @Autowired
    private AccountInfoServiceImpl accountInfoService;
    @Autowired
    private FundInfoServiceImpl fundInfoService;//a
    @Autowired
    private InvestorInfoServiceImpl investorInfoService;//b
    @Autowired
    private InvestorBankInfoServiceImpl investorBankInfoService;//b
    @Autowired
    private FundNetValueInfoServiceImpl fundNetValueInfoService;//c
    @Autowired
    private CustShareInfoServiceImpl custShareInfoService;//d
    @Autowired
    private TgAccountBalanceInfoServiceImpl tgAccountBalanceInfoService;//e
    @Autowired
    private TgAccountSeqInfoServiceImpl tgAccountSeqInfoService;//f
    @Autowired
    private MjAccountBalanceInfoServiceImpl mjAccountBalanceInfoService;//g
    @Autowired
    private MjAccountSeqInfoServiceImpl mjAccountSeqInfoService;//h
    @Autowired
    private FundTradeInfoServiceImpl fundTradeInfoService;//i
    @Autowired
    private FundValueTableDataInfoServiceImpl fundValueTableDataInfoService;//j
    @Autowired
    private FundProfitInfoServiceImpl fundProfitInfoService;//j
    @Autowired
    private DataDictionarySellerServiceImpl sellerService;
    @Autowired
    private FundFeeDataInfoServiceImpl fundFeeDataInfoService;//j
    @Autowired
    private FundOpenInfoServiceImpl fundOpenInfoService;
    @Autowired
    private DataDictionaryOpenStateServiceImpl openStateService;
    @Autowired
    private FundValuationServiceImpl fundValuationService;
    @Autowired
    private DataDictionaryTypeOfFundValuationServiceImpl typeOfFundValuationService;

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

    @Override
    public R initTenantDataSingle(TenantEscrowAuthorizationInfoDto tenant) {
        log.info("建投托管数据初始化...");
        getDataFromCsc(tenant, CustodyContants.INIT_BY_MONTH_LOOP_TIME); //先都拿1年，客户有需求再增加到3年
        log.info("建投托管数据初始化结束:");
        return R.ok("建投托管数据初始化结束！");
    }

    private static final ThreadLocal<Map<String, String>> fundInnerCodeAndCodeTL = new ThreadLocal<>();
    private static final ThreadLocal<List<String>> accountNumTL = new ThreadLocal<>();

    private ObjectMapper objectMapper = new ObjectMapper();
    public CscAppSecretDTO getCscAppSecretDTO(TenantEscrowAuthorizationInfoDto tenant){
        String tenantAppSecret = tenant.getAppSecret();
        if (ObjectUtil.isEmpty(tenantAppSecret)){
            return null;
        }
        CscAppSecretDTO cscAppSecretDTO = new CscAppSecretDTO();
        try {
            cscAppSecretDTO = objectMapper.readValue(tenantAppSecret, CscAppSecretDTO.class);
        } catch (IOException e) {
            log.error("解析账密{}失败!{}", cscAppSecretDTO,  e);
        }
        return cscAppSecretDTO;
    }

    private void getDataFromCsc(TenantEscrowAuthorizationInfoDto tenant, int loopTime) {
        String trustNo = "38";
        try {
            //15 资金账户基本信息表 account_info，16 托管⼾银⾏账⼾余额信息表（TGAccount_balance_info,MJAccount_balance_info）
            processAccountInfoData(tenant, trustNo);
            //1 基金产品信息表（fund_info）
            processFundInfoData(tenant, trustNo);
            //2 基金出资人信息表（investor_info,investor_bank_info）
            processInvestorInfoData(tenant, trustNo);
            //3 基金净值信息表（fund_net_value_info）
            processFundNetValueInfoData(tenant, trustNo, loopTime);
            //4 基金持有信息表（cust_share_info）
            processCustShareInfoData(tenant, trustNo);
            //19 募集⼾流⽔表（MJAccount_seq_info）
            processMJAccountSeqInfoData(tenant, trustNo, loopTime);
            //17 托管⼾流⽔表（TGAccount_seq_info）
            processTGAccountSeqInfoData(tenant, trustNo, loopTime);
            //18 基金交易确认信息表（fund_trade_info）
            processFundTradeInfoData(tenant, trustNo, loopTime);
            //20 基金估值报表数据表 fund_value_table_data_info
            processFundValueTableDataInfoData(tenant, trustNo, loopTime);
            //14 业绩报酬信息表(fund_profit_info)
            processFundProfitInfoData(tenant, trustNo, loopTime);
            //基金费用查询 ( fund_fee_data_info )
            processFundFeeDataInfoData(tenant, trustNo, loopTime);
            //基金开放日信息表（fund_open_info）
            processFundOpenInfoData(tenant, trustNo, loopTime);
        } catch (Exception e) {
            log.error("建投托管数据拉取失败:", e);
        } finally {
            //todo tl的remove
            fundInnerCodeAndCodeTL.remove();
            accountNumTL.remove();
        }
    }
    private void getUpdateDataFromCsc(TenantEscrowAuthorizationInfoDto tenant, int loopTime) {
        String trustNo = "38";
        try {
            //15 资金账户基本信息表 account_info，16 托管⼾银⾏账⼾余额信息表（TGAccount_balance_info,MJAccount_balance_info）
            processAccountInfoData(tenant, trustNo);
            //1 基金产品信息表（fund_info）
            processFundInfoData(tenant, trustNo);
            //2 基金出资人信息表（investor_info,investor_bank_info）
            processInvestorInfoData(tenant, trustNo);
            //4 基金持有信息表（cust_share_info）
            processCustShareInfoData(tenant, trustNo);
            //19 募集⼾流⽔表（MJAccount_seq_info）
            processMJAccountSeqInfoData(tenant, trustNo, loopTime);
            //17 托管⼾流⽔表（TGAccount_seq_info）
            processTGAccountSeqInfoData(tenant, trustNo, loopTime);
            //18 基金交易确认信息表（fund_trade_info）
            processFundTradeInfoData(tenant, trustNo, loopTime);
            //20 基金估值报表数据表 fund_value_table_data_info
            processFundValueTableDataInfoData(tenant, trustNo, loopTime);
            //14 业绩报酬信息表(fund_profit_info)
            processFundProfitInfoData(tenant, trustNo, loopTime);
            //基金费用查询 ( fund_fee_data_info )
            processFundFeeDataInfoData(tenant, trustNo, loopTime);
            //基金开放日信息表（fund_open_info）
            processFundOpenInfoData(tenant, trustNo, loopTime);
        } catch (Exception e) {
            log.error("建投托管数据拉取失败:", e);
        } finally {
            //todo tl的remove
            fundInnerCodeAndCodeTL.remove();
            accountNumTL.remove();
        }
    }

    private void processFundOpenInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo, int loopTime) {
        CscAppSecretDTO cscAppSecretDTO = getCscAppSecretDTO(tenant);
        String apiKey = cscAppSecretDTO.getApiKey();
        String apiSecret = cscAppSecretDTO.getApiSecret();
        String encryptKey = cscAppSecretDTO.getEncryptKey();
        List<String> fundCodes = accountInfoService.queryFundCodeByTrustNo(trustNo, tenant.getTenantName());
        String startDate;
        String endDate;
        LocalDate localDate = LocalDate.now();
        LocalDate lastMonth;
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        endDate = dateTimeFormatter.format(localDate);
        for (int i = 0; i < loopTime; i++) {
            lastMonth = localDate.minusMonths(1);
            startDate = dateTimeFormatter.format(lastMonth);
            String finalStartDate = startDate;
            String finalEndDate = endDate;
            for (String fundCode : fundCodes) {
                try {
                    //1、封装请求参数
                    HashMap<String, Object> params = new HashMap<>();
                    int reqNum = 500;
                    int reqPageno = 1;
                    //2、获取远端数据
                    boolean flag = true;
                    while (flag) {
                        params.put("fundCode", fundCode);
                        params.put("openDayBegin", finalStartDate);
                        params.put("openDayEnd", finalEndDate);
                        params.put("reqNum", reqNum);
                        params.put("reqPageno", reqPageno);
                        //对入参body进行加密，第二个参数代表加密类型，1代表SM4加密，2代表blowfish加密。
                        String body = SM4Util.encryptECB(JsonUtil.toJsonString(params), encryptKey);
                        //拼接url
                        String url = UrlConstant.ERP_URL + CSCConstants.FUND_OPEN_INFO_API;
                        //传入url和body，调用httpClient请求返回结果hah
                        String result = TestHttpUtil.callNoAuthFunc(url, null, body, true, true, apiSecret, apiKey);
                        //解密result
                        Map<String, Object> resultMap = JsonUtil.toMap(SM4Util.decryptECB(result, encryptKey));
                        saveInvokeRecord(tenant, trustNo, CSCConstants.FUND_OPEN_INFO_API, "", params, resultMap);
                        if ("0000".equals(resultMap.get("retCode"))) {
                            Map<String, Object> data = JsonUtil.toMap(JsonUtil.toJsonString(resultMap.get("data")));
                            List<LinkedHashMap<String,String>> remoteData = (List<LinkedHashMap<String,String>>)data.get("result");
                            //List<JSONObject> remoteData = JSONObject.parseArray(data.get("result").toString(), JSONObject.class);
                            Integer totalCount = (Integer) data.get("totalCount");
                            if (reqNum * reqPageno > totalCount) {
                                flag = false;
                            }
                            if (!CollectionUtils.isEmpty(remoteData)) {
                                log.info("中信建投获取fundOpenInfo数据{}条", remoteData.size());
                                //3、封装成标准表的对象
                                List<FundOpenInfoEntity> entities = getFundOpenInfo(tenant, remoteData, trustNo, fundCode);
                                log.info("中信建投封装fundOpenInfo数据{}条", entities.size());
                                //4、调用 basicservice 的保存数据接口
                                fundOpenInfoService.saveData(null, entities);
                            }
                            reqPageno++;
                        } else {
                            log.info("fundOpenInfo接口报错：" + JSON.toJSONString(resultMap.get("retMsg")));
                            Map<String, Object> result1 = new HashMap<>();
                            Object obj = resultMap.get("retMsg");
                            result1.put("data", obj);
                            pullDataFailureLogService.saveErrorData(tenant.getTenantName(), result1);
                            return;
                        }
                    }
                } catch (Exception e) {
                    log.error("中信建投获取FundOpenInfo数据失败！:", e);
                }
            }
            // TODO: 2022/1/13 加一个处理失败的日志统计表
            localDate = lastMonth;
            endDate = startDate;
        }
    }

    private List<FundOpenInfoEntity> getFundOpenInfo(TenantEscrowAuthorizationInfoDto tenant, List<LinkedHashMap<String,String>> result2, String trustNo, String innerFundCode) {
        //获取数据字典
        //开放日类型字典
        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<>();
        for (LinkedHashMap<String,String> dataMap : result2){
            //fundCode 应取基金产品信息表（fund_info）中基金内部代码字段为该请求参数的基金代码的记录的基金备案编码fund_code字段
            String fundCode = "";
            FundInfoEntity fundInfoEntity = fundInfoService.queryByInnerFundCode(trustNo, tenant.getTenantName(), innerFundCode);
            if (ObjectUtils.isEmpty(fundInfoEntity)){
                fundCode = fundInfoEntity.getFundCode();
            }
            //转义开放日类型
            String openType = MatchDataDictionaryKeyUtil.getKey(typeOfOpenDayDic, dataMap.get("openType"));
            //转义开放状态
            String openStatus = MatchDataDictionaryKeyUtil.getKey(openType, openStateDic, dataMap.get("openStatus"));
            entityList.add(FundOpenInfoEntity.builder()
                    .fundName(dataMap.get("fundCode"))
                    .openType(openType)
                    .fundOpenDate(dataMap.get("openDay"))
                    .openStatus(openStatus)
                    .remark(dataMap.get("remark"))
                    .innerFundCode(innerFundCode)
                    .fundCode(fundCode)
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(new Date())
                    .updateTime(new Date())
                    .build());

        }
        return entityList;
    }

    private void processFundFeeDataInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo, int loopTime) {
        CscAppSecretDTO cscAppSecretDTO = getCscAppSecretDTO(tenant);
        String apiKey = cscAppSecretDTO.getApiKey();
        String apiSecret = cscAppSecretDTO.getApiSecret();
        String encryptKey = cscAppSecretDTO.getEncryptKey();
        List<String> fundCodes = accountInfoService.queryFundCodeByTrustNo(trustNo, tenant.getTenantName());
        String startDate;
        String endDate;
        LocalDate localDate = LocalDate.now();
        LocalDate lastMonth;
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        endDate = dateTimeFormatter.format(localDate);
        for (int i = 0; i < loopTime; i++) {
            lastMonth = localDate.minusMonths(1);
            startDate = dateTimeFormatter.format(lastMonth);
            String finalStartDate = startDate;
            String finalEndDate = endDate;
            for (String fundCode : fundCodes) {
                try {
                    //1、封装请求参数
                    HashMap<String, Object> params = new HashMap<>();
                    int reqNum = 300;
                    int reqPageno = 1;
                    //2、获取远端数据
                    boolean flag = true;
                    while (flag) {
                        params.put("fundCode", fundCode);
                        params.put("beginDate", finalStartDate);
                        params.put("endDate", finalEndDate);
                        params.put("reqNum", reqNum);
                        params.put("reqPageno", reqPageno);
                        //对入参body进行加密，第二个参数代表加密类型，1代表SM4加密，2代表blowfish加密。
                        String body = SM4Util.encryptECB(JsonUtil.toJsonString(params), encryptKey);
                        //拼接url
                        String url = UrlConstant.ERP_URL + CSCConstants.FUND_FEE_DATA_INFO_API;
                        //传入url和body，调用httpClient请求返回结果hah
                        String result = TestHttpUtil.callNoAuthFunc(url, null, body, true, true, apiSecret, apiKey);
                        //解密result
                        Map<String, Object> resultMap = JsonUtil.toMap(SM4Util.decryptECB(result, encryptKey));
                        if ("0000".equals(resultMap.get("retCode"))) {
                            saveInvokeRecord(tenant, trustNo, CSCConstants.FUND_FEE_DATA_INFO_API, "", params, resultMap);
                            Map<String, Object> data = JsonUtil.toMap(JsonUtil.toJsonString(resultMap.get("data")));
                            List<JSONObject> result2 = (List<JSONObject>) data.get("result");
                            Integer totalCount = (Integer) data.get("totalCount");
                            if (reqNum * reqPageno > totalCount) {
                                flag = false;
                            }
                            if (!CollectionUtils.isEmpty(result2)) {
                                log.info("中信建投获取fundFeeDataInfo数据{}条", result2.size());
                                //3、封装成标准表的对象
                                List<FundFeeDataInfoEntity> entities = getFundFeeDataInfo(tenant, result2, trustNo);
                                log.info("中信建投封装fundFeeDataInfo数据{}条", entities.size());
                                //4、调用 basicservice 的保存数据接口
                                fundFeeDataInfoService.saveData(null, entities);
                            }
                            reqPageno++;
                        } else {
                            log.info("中信建投FundFeeDataInfo接口报错：" + JSON.toJSONString(resultMap.get("retMsg")));
                            Map<String, Object> result1 = new HashMap<>();
                            Object obj = resultMap.get("retMsg");
                            result1.put("data", obj);
                            pullDataFailureLogService.saveErrorData(tenant.getTenantName(), result1);
                            return;
                        }
                    }
                } catch (Exception e) {
                    log.error("中信建投获取fundFeeDataInfo数据失败！", e);
                }
            }
            // TODO: 2022/1/13 加一个处理失败的日志统计表
            localDate = lastMonth;
            endDate = startDate;
        }
    }

    private List<FundFeeDataInfoEntity> getFundFeeDataInfo(TenantEscrowAuthorizationInfoDto tenant, List<JSONObject> result2, String trustNo) {
        //获取字典
        //封装数据
        List<FundFeeDataInfoEntity> entityList = new ArrayList<>();
        Map<String, String> remoteDataMap;
        List<JSONObject> datas = JSONObject.parseArray(JSONObject.toJSONString(result2), JSONObject.class);
        for (JSONObject remoteData : datas) {
            remoteDataMap = JSONObject.toJavaObject(remoteData, Map.class);
            String fundCode = fundInfoService.getFundCodeByInnerFundCode(remoteDataMap.get("fundCode"), trustNo);
            //管理费
            entityList.add(FundFeeDataInfoEntity.builder()
                    .confirmDate(remoteDataMap.get("confDate"))
                    .innerFundCode(remoteDataMap.get("fundCode"))
                    .fundName(remoteDataMap.get("fundName"))
                    .fareDebit(BigDecimalUtil.obj2BigDecimalTrunToZero(remoteDataMap.get("managementFee")))
                    .subjectCode("GLF")
                    .subjectName("管理费")
                    .fundCode(fundCode)
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(new Date())
                    .updateTime(new Date())
                    .build());
            //投顾费
            entityList.add(FundFeeDataInfoEntity.builder()
                    .confirmDate(remoteDataMap.get("confDate"))
                    .innerFundCode(remoteDataMap.get("fundCode"))
                    .fundName(remoteDataMap.get("fundName"))
                    .fareDebit(BigDecimalUtil.obj2BigDecimalTrunToZero(remoteDataMap.get("investmentFee")))
                    .subjectCode("TGF2")
                    .subjectName("投顾费")
                    .fundCode(fundCode)
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(new Date())
                    .updateTime(new Date())
                    .build());
            //销售服务费
            entityList.add(FundFeeDataInfoEntity.builder()
                    .confirmDate(remoteDataMap.get("confDate"))
                    .innerFundCode(remoteDataMap.get("fundCode"))
                    .fundName(remoteDataMap.get("fundName"))
                    .fareDebit(BigDecimalUtil.obj2BigDecimalTrunToZero(remoteDataMap.get("salesFee")))
                    .subjectCode("XSF")
                    .subjectName("销售服务费")
                    .fundCode(fundCode)
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(new Date())
                    .updateTime(new Date())
                    .build());
            //托管费
            entityList.add(FundFeeDataInfoEntity.builder()
                    .confirmDate(remoteDataMap.get("confDate"))
                    .innerFundCode(remoteDataMap.get("fundCode"))
                    .fundName(remoteDataMap.get("fundName"))
                    .fareDebit(BigDecimalUtil.obj2BigDecimalTrunToZero(remoteDataMap.get("custodianFee")))
                    .subjectCode("TGF")
                    .subjectName("托管费")
                    .fundCode(fundCode)
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(new Date())
                    .updateTime(new Date())
                    .build());
            //托管费
            entityList.add(FundFeeDataInfoEntity.builder()
                    .confirmDate(remoteDataMap.get("confDate"))
                    .innerFundCode(remoteDataMap.get("fundCode"))
                    .fundName(remoteDataMap.get("fundName"))
                    .fareDebit(BigDecimalUtil.obj2BigDecimalTrunToZero(remoteDataMap.get("outsourcingFee")))
                    .subjectCode("WBF")
                    .subjectName("外包服务费")
                    .fundCode(fundCode)
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(new Date())
                    .updateTime(new Date())
                    .build());
        }
        return entityList;
    }

    private void processFundProfitInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo, int loopTime) {
        CscAppSecretDTO cscAppSecretDTO = getCscAppSecretDTO(tenant);
        String apiKey = cscAppSecretDTO.getApiKey();
        String apiSecret = cscAppSecretDTO.getApiSecret();
        String encryptKey = cscAppSecretDTO.getEncryptKey();
        String startDate;
        String endDate;
        LocalDate localDate = LocalDate.now();
        LocalDate lastMonth;
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        endDate = dateTimeFormatter.format(localDate);
        for (int i = 0; i < loopTime; i++) {
            lastMonth = localDate.minusMonths(1);
            startDate = dateTimeFormatter.format(lastMonth);
            String finalStartDate = startDate;
            String finalEndDate = endDate;
            try {
                //1、封装请求参数
                HashMap<String, Object> params = new HashMap<>();
                int reqNum = 300;
                int reqPageno = 1;

                //2、获取远端数据
                boolean flag = true;
                while (flag) {
                    params.put("confDateBegin", finalStartDate);
                    params.put("confDateEnd", finalEndDate);
                    params.put("reqNum", reqNum);
                    params.put("reqPageno", reqPageno);
                    //对入参body进行加密，第二个参数代表加密类型，1代表SM4加密，2代表blowfish加密。
                    String body = SM4Util.encryptECB(JsonUtil.toJsonString(params), encryptKey);
                    //拼接url
                    String url = UrlConstant.ERP_URL + CSCConstants.FUND_PROFIT_INFO_API;
                    //传入url和body，调用httpClient请求返回结果hah
                    String result = TestHttpUtil.callNoAuthFunc(url, null, body, true, true, apiSecret, apiKey);
                    //解密result
                    Map<String, Object> resultMap = JsonUtil.toMap(SM4Util.decryptECB(result, encryptKey));
                    if ("0000".equals(resultMap.get("retCode"))) {
                        saveInvokeRecord(tenant, trustNo, CSCConstants.FUND_PROFIT_INFO_API, "", params, resultMap);
                        Map<String, Object> data = JsonUtil.toMap(JsonUtil.toJsonString(resultMap.get("data")));
                        List<JSONObject> result2 = (List<JSONObject>) data.get("result");
                        Integer totalCount = (Integer) data.get("totalCount");
                        if (reqNum * reqPageno > totalCount) {
                            flag = false;
                        }
                        if (!CollectionUtils.isEmpty(result2)) {
                            //3、封装成标准表的对象
                            List<FundProfitInfoEntity> entities = getFundProfitInfo(tenant, result2, trustNo);
                            //4、调用 basicservice 的保存数据接口
                            fundProfitInfoService.saveData(null, entities);
                        }
                        reqPageno++;
                    } else {
                        log.info("fundProfitInfo接口报错：" + JSON.toJSONString(resultMap.get("retMsg")));
                        Map<String, Object> result1 = new HashMap<>();
                        Object obj = resultMap.get("retMsg");
                        result1.put("data", obj);
                        pullDataFailureLogService.saveErrorData(tenant.getTenantName(), result1);
                        return;
                    }
                }
            } catch (Exception e) {
                log.error("FundProfitInfoData:", e);
            }
            // TODO: 2022/1/13 加一个处理失败的日志统计表
            localDate = lastMonth;
            endDate = startDate;
        }
    }

    private List<FundProfitInfoEntity> getFundProfitInfo(TenantEscrowAuthorizationInfoDto tenant, List<JSONObject> remoteDatas, String trustNo) {
        //1、获取字典表数据
        Map<String, String> serviceDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.SELLER_SERVICE, "中信建投");
        Map<String, String> accrul = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.ACCRUAL_WAY_SERVICE, trustNo);
        Map<String, String> pay = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.PAYMENT_WAY_SERVICE, trustNo);

        //2、封装数据
        List<FundProfitInfoEntity> result = new ArrayList<>();
        Map<String, String> remoteDataMap;
        Date now = new Date();
        String s = JSONObject.toJSONString(remoteDatas);
        List<JSONObject> datas = JSONObject.parseArray(s, JSONObject.class);
        for (JSONObject remoteData : datas) {
            remoteDataMap = JSONObject.toJavaObject(remoteData, Map.class);
            String fundCode = fundInfoService.getFundCodeByInnerFundCode(remoteDataMap.get("fundCode"), trustNo);
            String name = fundInfoService.getFundNameByInnerFundCode(remoteDataMap.get("fundCode"), trustNo);
            log.info("getFundCodeByInnerFundCode from " + remoteDataMap.get("fundCode") + "to " + fundCode);
            log.info("销售商原值" + remoteDataMap.get("agencyNo"));
            log.info("销售商映射值" + MatchDataDictionaryKeyUtil.getKey(serviceDir, remoteDataMap.get("agencyNo")));

            String agencyName = sellerService.queryAgencyName("中信建投", remoteDataMap.get("agencyNo"));

            result.add(FundProfitInfoEntity.builder()
                    .confirmDate(remoteDataMap.get("confDate"))
                    .innerFundCode(remoteDataMap.get("fundCode"))
                    .fundName(name)
                    .agencyNo(MatchDataDictionaryKeyUtil.getKey(serviceDir, remoteDataMap.get("agencyNo")))
                    .agencyName(agencyName)
                    .fundAcco(remoteDataMap.get("fundAcco"))
                    .tradeAcco(remoteDataMap.get("tradeAcco"))
                    .branchCode(remoteDataMap.get("branchCode"))
                    .oriDate(remoteDataMap.get("dBeginDate"))
                    .triggerType(MatchDataDictionaryKeyUtil.getKey(accrul, remoteDataMap.get("triggerType")))
                    .shareType(MatchDataDictionaryKeyUtil.getKey(pay, remoteDataMap.get("shareType")))
                    .shares(new BigDecimal(remoteDataMap.get("shares") == null ? "0" : remoteDataMap.get("shares").replace(",", "")).setScale(2, BigDecimal.ROUND_HALF_UP))
                    .oriNav(new BigDecimal(remoteDataMap.get("oriNav") == null ? "0" : remoteDataMap.get("oriNav").replace(",", "")).setScale(4, BigDecimal.ROUND_HALF_UP))
                    .oriTotalNav(new BigDecimal(remoteDataMap.get("oriTotalNav") == null ? "0" : remoteDataMap.get("oriTotalNav").replace(",", "")).setScale(4, BigDecimal.ROUND_HALF_UP))
                    .nav(new BigDecimal(remoteDataMap.get("nav") == null ? "0" : remoteDataMap.get("nav").replace(",", "")).setScale(4))
                    .totalNav(new BigDecimal(remoteDataMap.get("totalNav") == null ? "0" : remoteDataMap.get("totalNav").replace(",", "")).setScale(4, BigDecimal.ROUND_HALF_UP))
                    .factBalance(new BigDecimal(remoteDataMap.get("rewardAmount") == null ? "0" : remoteDataMap.get("rewardAmount").replace(",", "")).setScale(2, BigDecimal.ROUND_HALF_UP))
                    .costPrice(new BigDecimal(remoteDataMap.get("navReward") == null ? "0" : remoteDataMap.get("navReward").replace(",", "")).setScale(2, BigDecimal.ROUND_HALF_UP))
                    .oriCserialNo(remoteDataMap.get("originalNo"))
                    .cserialNo(remoteDataMap.get("cserialNo"))
                    .fundCode(fundCode)
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(now)
                    .updateTime(now)
                    .build());
        }
        return result;
    }

    public void processFundValueTableDataInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo, int loopNum) {
        CscAppSecretDTO cscAppSecretDTO = getCscAppSecretDTO(tenant);
        String apiKey = cscAppSecretDTO.getApiKey();
        String apiSecret = cscAppSecretDTO.getApiSecret();
        String encryptKey = cscAppSecretDTO.getEncryptKey();
        List<String> fundCodes = accountInfoService.queryFundCodeByTrustNo(trustNo, tenant.getTenantName());
        String curDay;
        LocalDate localDate = LocalDate.now();
        //将loopNum的循环次数转变为日期
        loopNum = loopNum == 1 ? 31 : 365;
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        for (int i = 0; i < loopNum; i++) {
            curDay = dateTimeFormatter.format(localDate);
            String finalCurDay = curDay;
            try {
                //1、封装请求参数
                HashMap<String, Object> params = new HashMap<>();
                for (String fundCode : fundCodes) {
                    if (StringUtils.isBlank(fundCode)) {
                        continue;
                    }
                    //2、获取远端数据
                    params.put("fundCode", fundCode);
                    params.put("valDate", finalCurDay);
                    //对入参body进行加密，第二个参数代表加密类型，1代表SM4加密，2代表blowfish加密。
                    String body = SM4Util.encryptECB(JsonUtil.toJsonString(params), encryptKey);
                    //拼接url
                    String url = UrlConstant.ERP_URL + CSCConstants.FUND_VALUE_TABLE_DATA_INFO_API;
                    //传入url和body，调用httpClient请求返回结果hah
                    String result = TestHttpUtil.callNoAuthFunc(url, null, body, true, true, apiSecret, apiKey);
                    //解密result
                    Map<String, Object> resultMap = JsonUtil.toMap(SM4Util.decryptECB(result, encryptKey));
                    if ("0000".equals(resultMap.get("retCode"))) {
                        saveInvokeRecord(tenant, trustNo, CSCConstants.FUND_VALUE_TABLE_DATA_INFO_API, "", params, resultMap);
                        Map<String, Object> data = JsonUtil.toMap(JsonUtil.toJsonString(resultMap.get("data")));
                        List<JSONObject> result2 = (List<JSONObject>) data.get("result");
                        if (!CollectionUtils.isEmpty(result2)) {
                            //3、封装成标准表的对象
                            List<FundValueTableDataInfoEntity> entities = getFundValueTableDataInfo(tenant, result2, trustNo);
                            List<FundValuationEntity> fundValuationEntities = getFundvaluationInfo(tenant.getTenantName(), result2, trustNo);
                            //4、调用 basicservice 的保存数据接口
                            fundValueTableDataInfoService.saveData(null, entities);
                            fundValuationService.saveData(null, fundValuationEntities);
                        }
                    } else {
                        log.info("fundValueTableDataInfo接口报错：" + JSON.toJSONString(resultMap.get("retMsg")));
                        Map<String, Object> result1 = new HashMap<>();
                        Object obj = resultMap.get("retMsg");
                        result1.put("data", obj);
                        pullDataFailureLogService.saveErrorData(tenant.getTenantName(), result1);
                        continue;
                    }
                }
            } catch (Exception e) {
                log.error("fundValueTableDataInfo:", e);
            }
            localDate = localDate.minusDays(1);
        }
    }

    private List<FundValuationEntity> getFundvaluationInfo(String tenantName, List<JSONObject> remoteDatas, String trustNo) {
        //获取数据字典
        Map<String, String> typeOfFundValuationDic = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.TYPE_OF_FUND_VALUATION, trustNo);
        Map<String, String> kmCodeNameMap = typeOfFundValuationService.queryKeyValue();
        //封装数据
        List<FundValuationEntity> result = new ArrayList<>();
        Map<String, String> remoteDataMap;
        Date now = new Date();
        String s = JSONObject.toJSONString(remoteDatas);
        List<JSONObject> datas = JSONObject.parseArray(s, JSONObject.class);
        for (JSONObject remoteData : datas) {
            remoteDataMap = JSONObject.toJavaObject(remoteData, Map.class);
            log.info("remoteDataMap" + JSON.toJSONString(remoteDataMap));
            String fundCode = fundInfoService.getFundCodeByInnerFundCode(remoteDataMap.get("fundCode"), trustNo);
            String fundName = fundInfoService.getFundNameByInnerFundCode(remoteDataMap.get("fundCode"), trustNo);
            log.info("getFundCodeByInnerFundCode from " + remoteDataMap.get("fundCode") + "to " + fundCode);
            String kmCode = MatchDataDictionaryKeyUtil.getKey(typeOfFundValuationDic, remoteDataMap.get("subjectCode"));
            String KmName = MatchDataDictionaryKeyUtil.getKey(kmCodeNameMap, kmCode);
            if (StringUtils.isBlank(kmCode)){
                continue;
            }
            result.add(FundValuationEntity.builder()
                    .innerFundCode(remoteDataMap.get("fundCode"))
                    .valueDate(remoteDataMap.get("valDate"))
                    .fundName(fundName)
                    .kmCode(kmCode)
                    .kmName(KmName)
                    .amount(BigDecimalUtil.obj2BigDecimal(remoteDataMap.get("quantity")))
                    .perCost(BigDecimalUtil.obj2BigDecimal(remoteDataMap.get("costPerUnit")))
                    .portCost(BigDecimalUtil.str2BigDecimal(remoteDataMap.get("cost")))
                    .costBi(BigDecimalUtil.obj2BigDecimal(remoteDataMap.get("costNetVal"), 4))
                    .vapPrice(BigDecimalUtil.str2BigDecimal(remoteDataMap.get("marketPrice")))
                    .portMv(BigDecimalUtil.str2BigDecimal(remoteDataMap.get("marketVal")))
                    .mvBl(BigDecimalUtil.obj2BigDecimal(remoteDataMap.get("marketValNetVal"), 4))
                    .portIv(BigDecimalUtil.str2BigDecimal(remoteDataMap.get("addedVal")))
                    .suspension(remoteDataMap.get("stopInfo"))
                    .fundCode(fundCode)
                    .trustNo(trustNo)
                    .admin(tenantName)
                    .createTime(now)
                    .updateTime(now)
                    .build());
        }
        return result;
    }

    private List<FundValueTableDataInfoEntity> getFundValueTableDataInfo(TenantEscrowAuthorizationInfoDto tenant, List<JSONObject> remoteDatas, String trustNo) {
        //封装数据
        List<FundValueTableDataInfoEntity> result = new ArrayList<>();
        Map<String, String> remoteDataMap;
        Date now = new Date();
        String s = JSONObject.toJSONString(remoteDatas);
        List<JSONObject> datas = JSONObject.parseArray(s, JSONObject.class);
        for (JSONObject remoteData : datas) {
            remoteDataMap = JSONObject.toJavaObject(remoteData, Map.class);
            log.info("remoteDataMap" + JSON.toJSONString(remoteDataMap));
            String fundCode = fundInfoService.getFundCodeByInnerFundCode(remoteDataMap.get("fundCode"), trustNo);
            String fundName = fundInfoService.getFundNameByInnerFundCode(remoteDataMap.get("fundCode"), trustNo);
            log.info("getFundCodeByInnerFundCode from " + remoteDataMap.get("fundCode") + "to " + fundCode);

            result.add(FundValueTableDataInfoEntity.builder()
                    .innerFundCode(remoteDataMap.get("fundCode"))
                    .valueDate(remoteDataMap.get("valDate"))
                    .fundName(fundName)
                    .kmCode(remoteDataMap.get("subjectCode"))
                    .kmName(remoteDataMap.get("subjectName"))
                    .amount(BigDecimalUtil.obj2BigDecimal(remoteDataMap.get("quantity")))
                    .perCost(BigDecimalUtil.obj2BigDecimal(remoteDataMap.get("costPerUnit")))
                    .portCost(BigDecimalUtil.str2BigDecimal(remoteDataMap.get("cost")))
                    .costBi(BigDecimalUtil.obj2BigDecimal(remoteDataMap.get("costNetVal"), 4))
                    .vapPrice(BigDecimalUtil.str2BigDecimal(remoteDataMap.get("marketPrice")))
                    .portMv(BigDecimalUtil.str2BigDecimal(remoteDataMap.get("marketVal")))
                    .mvBl(BigDecimalUtil.obj2BigDecimal(remoteDataMap.get("marketValNetVal"), 4))
                    .portIv(BigDecimalUtil.str2BigDecimal(remoteDataMap.get("addedVal")))
                    .suspension(remoteDataMap.get("stopInfo"))
                    .fundCode(fundCode)
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(now)
                    .updateTime(now)
                    .build());
        }
        return result;
    }

    public void processFundTradeInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo, int loopTime) {
        CscAppSecretDTO cscAppSecretDTO = getCscAppSecretDTO(tenant);
        String apiKey = cscAppSecretDTO.getApiKey();
        String apiSecret = cscAppSecretDTO.getApiSecret();
        String encryptKey = cscAppSecretDTO.getEncryptKey();
        String startDate;
        String endDate;
        LocalDate localDate = LocalDate.now();
        LocalDate lastMonth;
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        endDate = dateTimeFormatter.format(localDate);
        for (int i = 0; i < loopTime; i++) {
            lastMonth = localDate.minusMonths(1);
            startDate = dateTimeFormatter.format(lastMonth);
            String finalStartDate = startDate;
            String finalEndDate = endDate;
            try {
                //1、封装请求参数
                HashMap<String, Object> params = new HashMap<>();
                int reqNum = 300;
                int reqPageno = 1;

                //2、获取远端数据
                boolean flag = true;
                while (flag) {
                    params.put("reqNum", reqNum);
                    params.put("reqPageno", reqPageno);
                    params.put("confDateBedin", finalStartDate);
                    params.put("confDateEnd", finalEndDate);
                    //对入参body进行加密，第二个参数代表加密类型，1代表SM4加密，2代表blowfish加密。
                    String body = SM4Util.encryptECB(JsonUtil.toJsonString(params), encryptKey);
                    //拼接url
                    String url = UrlConstant.ERP_URL + CSCConstants.FUND_TRADE_INFO_API;
                    //传入url和body，调用httpClient请求返回结果hah
                    String result = TestHttpUtil.callNoAuthFunc(url, null, body, true, true, apiSecret, apiKey);
                    //解密result
                    Map<String, Object> resultMap = JsonUtil.toMap(SM4Util.decryptECB(result, encryptKey));
                    if ("0000".equals(resultMap.get("retCode"))) {
                        saveInvokeRecord(tenant, trustNo, CSCConstants.FUND_TRADE_INFO_API, "", params, resultMap);
                        Map<String, Object> data = JsonUtil.toMap(JsonUtil.toJsonString(resultMap.get("data")));
                        List<JSONObject> result2 = (List<JSONObject>) data.get("result");
                        Integer totalCount = (Integer) data.get("totalCount");
                        if (reqNum * reqPageno > totalCount) {
                            flag = false;
                        }
                        if (!CollectionUtils.isEmpty(result2)) {
                            //3、封装成标准表的对象
                            List<FundTradeInfoEntity> entities = getFundTradeInfo(tenant, result2, trustNo);
                            //4、调用 basicservice 的保存数据接口
                            fundTradeInfoService.saveData(null, entities);
                        }
                        reqPageno++;
                    } else {
                        log.info("fundTradeInfo接口报错：" + JSON.toJSONString(resultMap.get("retMsg")));
                        Map<String, Object> result1 = new HashMap<>();
                        Object obj = resultMap.get("retMsg");
                        result1.put("data", obj);
                        pullDataFailureLogService.saveErrorData(tenant.getTenantName(), result1);
                        return;
                    }
                }
            } catch (Exception e) {
                log.error("FundTradeInfoData:", e);
            }
            // TODO: 2022/1/13 加一个处理失败的日志统计表
            localDate = lastMonth;
            endDate = startDate;
        }
    }

    private List<FundTradeInfoEntity> getFundTradeInfo(TenantEscrowAuthorizationInfoDto tenant, List<JSONObject> remoteDatas, String trustNo) {
        //1、获取字典表数据
        Map<String, String> serviceDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.SELLER_SERVICE, "中信建投");
        Map<String, String> dividendDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.DIVIDEND_WAY_SERVICE, trustNo);
        Map<String, String> businessTypeDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.BUSINESS_NAME_SERVICE, trustNo);
        Map<String, String> ta = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.TA_LAUNCH_FLAG_SERVICE, trustNo);

        log.info("getFundTradeInfo" + JSON.toJSONString(remoteDatas));
        //2、封装数据
        List<FundTradeInfoEntity> result = new ArrayList<>();
        Map<String, String> remoteDataMap;
        Date now = new Date();
        String s = JSONObject.toJSONString(remoteDatas);
        List<JSONObject> datas = JSONObject.parseArray(s, JSONObject.class);
        for (JSONObject remoteData : datas) {
            remoteDataMap = JSONObject.toJavaObject(remoteData, Map.class);
            log.info("remoteDataMap" + JSON.toJSONString(remoteDataMap));
            String fundCode = fundInfoService.getFundCodeByInnerFundCode(remoteDataMap.get("fundCode"), trustNo);
            log.info("getFundCodeByInnerFundCode from " + remoteDataMap.get("fundCode") + "to " + fundCode);

            System.err.println("- " + remoteDataMap.get("agencyNo"));
            String agencyNo = MatchDataDictionaryKeyUtil.getKey(serviceDir, remoteDataMap.get("agencyNo"));
            System.err.println(agencyNo);

            result.add(FundTradeInfoEntity.builder()
                    .confirmDate(remoteDataMap.get("confDate"))
                    .requestDate(remoteDataMap.get("applyDate"))
                    .innerFundCode(remoteDataMap.get("fundCode"))
                    .fundName(remoteDataMap.get("fundName"))
                    .agencyNo(agencyNo)
                    .agencyName(remoteDataMap.get("agencyName"))
                    .fundAcco(remoteDataMap.get("fundAcco"))
                    .tradeAcco(remoteDataMap.get("tradeAcco"))
                    .taFlag(MatchDataDictionaryKeyUtil.getKey(ta, remoteDataMap.get("taFlag")))
                    .confirmStatus(remoteDataMap.get("confStatus"))
                    .bonusMethod(MatchDataDictionaryKeyUtil.getKey(dividendDir, remoteDataMap.get("bonusType")))
                    .applyBalance(new BigDecimal(remoteDataMap.get("balance") == null ? "0" : remoteDataMap.get("balance").replace(",", "")).setScale(2))
                    .applyShares(new BigDecimal(remoteDataMap.get("shares") == null ? "0" : remoteDataMap.get("shares").replace(",", "")).setScale(2))
                    .netValue(new BigDecimal(remoteDataMap.get("netValue") == null ? "0" : remoteDataMap.get("netValue").replace(",", "")).setScale(4))
                    .confirmBalance(new BigDecimal(remoteDataMap.get("confBalance") == null ? "0" : remoteDataMap.get("confBalance").replace(",", "")).setScale(2))
                    .confirmShares(new BigDecimal(remoteDataMap.get("confShares") == null ? "0" : remoteDataMap.get("confShares").replace(",", "")).setScale(2))
                    .tradeFare(new BigDecimal(remoteDataMap.get("charge") == null ? "0" : remoteDataMap.get("charge").replace(",", "")).setScale(2))
                    .profitBalance(new BigDecimal(remoteDataMap.get("achievementPay") == null ? "0" : remoteDataMap.get("achievementPay").replace(",", "")).setScale(2))
                    .totalFare(new BigDecimal(remoteDataMap.get("totalFare") == null ? "0" : remoteDataMap.get("totalFare").replace(",", "")).setScale(2))
                    .agencyFare(new BigDecimal(remoteDataMap.get("distributorCharge") == null ? "0" : remoteDataMap.get("distributorCharge").replace(",", "")).setScale(2))
                    .fundFare(new BigDecimal(remoteDataMap.get("fundcharge") == null ? "0" : remoteDataMap.get("fundcharge").replace(",", "")).setScale(2))
                    .registFare(new BigDecimal(remoteDataMap.get("managerCharge") == null ? "0" : remoteDataMap.get("managerCharge").replace(",", "")).setScale(2))
                    .cserialNo(remoteDataMap.get("cserialNo"))
                    .businessName(MatchDataDictionaryKeyUtil.getKey(businessTypeDir, remoteDataMap.get("busiFlag")))
                    .requestNo(remoteDataMap.get("originalNo"))
                    .fundCode(fundCode)
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(now)
                    .updateTime(now)
                    .build());
        }
        return result;
    }

    private void processTGAccountSeqInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo, int loopTime) {
        CscAppSecretDTO cscAppSecretDTO = getCscAppSecretDTO(tenant);
        String apiKey = cscAppSecretDTO.getApiKey();
        String apiSecret = cscAppSecretDTO.getApiSecret();
        String encryptKey = cscAppSecretDTO.getEncryptKey();
        List<String> fundCodes = accountInfoService.queryFundCodeByTrustNo(trustNo, tenant.getTenantName());
        String startDate;
        String endDate;
        LocalDate localDate = LocalDate.now();
        LocalDate lastMonth;
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        endDate = dateTimeFormatter.format(localDate);
        for (int i = 0; i < loopTime; i++) {
            lastMonth = localDate.minusMonths(1);
            startDate = dateTimeFormatter.format(lastMonth);
            String finalStartDate = startDate;
            String finalEndDate = endDate;
            for (String fundCode : fundCodes) {
                if (StringUtils.isEmpty(fundCode)) {
                    continue;
                }
                try {
                    //1、封装请求参数
                    HashMap<String, Object> params = new HashMap<>();
                    params.put("fundCode", fundCode);
                    params.put("startDate", finalStartDate);
                    params.put("endsDate", finalEndDate);
                    //对入参body进行加密，第二个参数代表加密类型，1代表SM4加密，2代表blowfish加密。
                    String body = SM4Util.encryptECB(JsonUtil.toJsonString(params), encryptKey);
                    //拼接url
                    String url = UrlConstant.ERP_URL + CSCConstants.TGACCOUNT_SEQ_API;
                    //传入url和body，调用httpClient请求返回结果hah
                    String result = TestHttpUtil.callNoAuthFunc(url, null, body, true, true, apiSecret, apiKey);
                    //解密result
                    Map<String, Object> resultMap = JsonUtil.toMap(SM4Util.decryptECB(result, encryptKey));
                    log.info("TGAccountSeqInfo结果：", JSON.toJSONString(resultMap));
                    if ("0000".equals(resultMap.get("retCode"))) {
                        saveInvokeRecord(tenant, trustNo, CSCConstants.TGACCOUNT_SEQ_API, "", params, resultMap);
                        Object obj = resultMap.get("data");
                        if (!Objects.isNull(obj) && obj instanceof LinkedHashMap) {
                            Map<String, Object> data = JsonUtil.toMap(JsonUtil.toJsonString(resultMap.get("data")));
                            List<JSONObject> result2 = (List<JSONObject>) data.get("result");
                            if (!CollectionUtils.isEmpty(result2)) {
                                //3、封装成标准表的对象
                                List<TgAccountSeqInfoEntity> entities = getTGAccountSeqInfo(tenant, result2, trustNo, fundCode);
                                //4、调用 basicservice 的保存数据接口
                                tgAccountSeqInfoService.saveData(null, entities);
                            }
                        }
                    } else if ("100005".equals(resultMap.get("retCode"))) {
                        log.info("TGAccountSeqInfo接口报错：" + JSON.toJSONString(resultMap.get("retMsg")));
                        Map<String, Object> result1 = new HashMap<>();
                        Object obj = resultMap.get("retMsg");
                        result1.put("data", obj);
                        pullDataFailureLogService.saveErrorData(tenant.getTenantName(), result1);
                        return;
                    } else {
                        continue;
                    }
                } catch (Exception e) {
                    log.error("processTGAccountSeqInfoData:", e);
                }
            }
            // TODO: 2022/1/13 加一个处理失败的日志统计表
            localDate = lastMonth;
            endDate = startDate;
        }
    }

    private List<TgAccountSeqInfoEntity> getTGAccountSeqInfo(TenantEscrowAuthorizationInfoDto tenant, List<JSONObject> remoteDatas, String trustNo, String fundCode) {
        //1、获取字典表数据
        Map<String, String> currencyDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.CURRENCY_SERVICE, trustNo);
        Map<String, String> paymentDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.PAYMENT_DIRECTION_SERVICE, trustNo);

        //2、封装数据
        List<TgAccountSeqInfoEntity> result = new ArrayList<>();
        Map<String, String> remoteDataMap;
        Date now = new Date();
        String s = JSONObject.toJSONString(remoteDatas);
        List<JSONObject> datas = JSONObject.parseArray(s, JSONObject.class);
        for (JSONObject remoteData : datas) {
            remoteDataMap = JSONObject.toJavaObject(remoteData, Map.class);
            String code = fundInfoService.getFundCodeByInnerFundCode(fundCode, trustNo);
            String fundName = fundInfoService.getFundNameByInnerFundCode(fundCode, trustNo);
            result.add(TgAccountSeqInfoEntity.builder()
                    .innerFundCode(code)
                    .fundName(fundName)
                    .transferInOut(MatchDataDictionaryKeyUtil.getKey(paymentDir, remoteDataMap.get("transferInOut")))
                    .account(remoteDataMap.get("bankAcco"))
                    .accountName(remoteDataMap.get("accName"))
                    .bankName(remoteDataMap.get("openBankName"))
                    .opAccount(remoteDataMap.get("optbankAcco"))
                    .opAccountName(remoteDataMap.get("optAccName"))
                    .balance(new BigDecimal(remoteDataMap.get("balance") == null ? "0" : remoteDataMap.get("balance").replace(",", "")).setScale(2))
                    .amount(new BigDecimal(remoteDataMap.get("amt") == null ? "0" : remoteDataMap.get("amt").replace(",", "")).setScale(2))
                    .transferDate(remoteDataMap.get("dealDate"))
                    .transferTime("00:00:00")
                    .summary(remoteDataMap.get("digest"))
                    .seqNo(StrUtil.getSeqNoWithoutNoRandom(remoteDataMap.get("applyNo")))
                    .fundCode(code)
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(now)
                    .updateTime(now)
                    .build());
        }
        return result;
    }

    private void processMJAccountSeqInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo, int loopTime) {
        CscAppSecretDTO cscAppSecretDTO = getCscAppSecretDTO(tenant);
        String apiKey = cscAppSecretDTO.getApiKey();
        String apiSecret = cscAppSecretDTO.getApiSecret();
        String encryptKey = cscAppSecretDTO.getEncryptKey();
        List<String> fundCodes = accountInfoService.queryFundCodeByTrustNo(trustNo, tenant.getTenantName());
        String startDate;
        String endDate;
        LocalDate localDate = LocalDate.now();
        LocalDate lastMonth;
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        endDate = dateTimeFormatter.format(localDate);
        for (int i = 0; i < loopTime; i++) {
            lastMonth = localDate.minusMonths(1);
            startDate = dateTimeFormatter.format(lastMonth);
            String finalStartDate = startDate;
            String finalEndDate = endDate;
            for (String fundCode : fundCodes) {
                if (StringUtils.isBlank(fundCode)) {
                    continue;
                }
                try {
                    //1、封装请求参数
                    HashMap<String, Object> params = new HashMap<>();
                    int reqNum = 300;
                    int reqPageno = 1;

                    //2、获取远端数据
                    boolean flag = true;
                    while (flag) {
                        params.put("fundCode", fundCode);
                        params.put("reqNum", reqNum);
                        params.put("reqPageno", reqPageno);
                        params.put("startDate", finalStartDate);
                        params.put("endsDate", finalEndDate);
                        //对入参body进行加密，第二个参数代表加密类型，1代表SM4加密，2代表blowfish加密。
                        String body = SM4Util.encryptECB(JsonUtil.toJsonString(params), encryptKey);
                        //拼接url
                        String url = UrlConstant.ERP_URL + CSCConstants.MJACCOUNT_SEQ_INFO_API;
                        //传入url和body，调用httpClient请求返回结果hah
                        String result = TestHttpUtil.callNoAuthFunc(url, null, body, true, true, apiSecret, apiKey);
                        //解密result
                        Map<String, Object> resultMap = JsonUtil.toMap(SM4Util.decryptECB(result, encryptKey));
                        if ("0000".equals(resultMap.get("retCode"))) {
                            saveInvokeRecord(tenant, trustNo, CSCConstants.MJACCOUNT_SEQ_INFO_API, "", params, resultMap);
                            Object obj = resultMap.get("data");
                            if (!Objects.isNull(obj) && obj instanceof LinkedHashMap) {
                                Map<String, Object> data = JsonUtil.toMap(JsonUtil.toJsonString(resultMap.get("data")));
                                List<JSONObject> result2 = (List<JSONObject>) data.get("result");
                                Integer totalCount = (Integer) data.get("totalCount");
                                if (reqNum * reqPageno > totalCount) {
                                    flag = false;
                                }
                                //3、封装成标准表的对象
                                List<MjAccountSeqInfoEntity> entities = getMJAccountSeqInfo(tenant, result2, trustNo, fundCode);
                                //4、调用 basicservice 的保存数据接口
                                mjAccountSeqInfoService.saveData(null, entities);
                                reqPageno++;
                            } else {
                                flag = false;
                            }
                        } else if ("100005".equals(resultMap.get("retCode"))) {
                            log.info("MJAccountSeqInfo接口报错：" + JSON.toJSONString(resultMap.get("retMsg")));
                            Map<String, Object> result1 = new HashMap<>();
                            Object obj = resultMap.get("retMsg");
                            result1.put("data", obj);
                            pullDataFailureLogService.saveErrorData(tenant.getTenantName(), result1);
                            return;
                        } else {
                            continue;
                        }
                    }
                } catch (Exception e) {
                    log.error("processMJAccountSeqInfoData:", e);
                }
            }
            // TODO: 2022/1/13 加一个处理失败的日志统计表
            localDate = lastMonth;
            endDate = startDate;
        }


    }

    private List<MjAccountSeqInfoEntity> getMJAccountSeqInfo(TenantEscrowAuthorizationInfoDto tenant, List<JSONObject> remoteDatas, String trustNo, String fundCode) {
        //1、获取字典表数据
        Map<String, String> currencyDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.CURRENCY_SERVICE, trustNo);
        Map<String, String> paymentDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.PAYMENT_DIRECTION_SERVICE, trustNo);

        //2、封装数据
        List<MjAccountSeqInfoEntity> result = new ArrayList<>();
        Map<String, String> remoteDataMap;
        Date now = new Date();
        String s = JSONObject.toJSONString(remoteDatas);
        List<JSONObject> datas = JSONObject.parseArray(s, JSONObject.class);
        for (JSONObject remoteData : datas) {
            remoteDataMap = JSONObject.toJavaObject(remoteData, Map.class);
            String transferInOut = null;
            if ("1".equals(remoteDataMap.get("transferInOut"))) {
                transferInOut = "2";
            } else if ("2".equals(remoteDataMap.get("transferInOut"))) {
                transferInOut = "1";
            }
            String code = fundInfoService.getFundCodeByInnerFundCode(fundCode, trustNo);
            result.add(MjAccountSeqInfoEntity.builder()
                    .innerFundCode(code)
                    .fundName(remoteDataMap.get("fundName"))
                    .transferInOut(transferInOut)
                    .balance(new BigDecimal(remoteDataMap.get("balance") == null ? "0" : remoteDataMap.get("balance").replace(",", "")).setScale(2))
                    .account(remoteDataMap.get("bankAcco"))
                    .accountName(remoteDataMap.get("accName"))
                    .bankName(remoteDataMap.get("openBankName"))
                    .opAccount(remoteDataMap.get("optBankAcco"))
                    .opAccountName(remoteDataMap.get("optAccName"))
                    .opBankName(remoteDataMap.get("optOpenBankName"))
                    .amount(new BigDecimal(remoteDataMap.get("amt") == null ? "0" : remoteDataMap.get("amt").replace(",", "")).setScale(2))
                    .transferDate(remoteDataMap.get("tradeDate"))
                    .transferTime(remoteDataMap.get("tradeTime").replaceAll("(\\d{2})(\\d{2})(\\d{2})", "$1:$2:$3"))
                    .summary(remoteDataMap.get("digest"))
                    .seqNo(StrUtil.getSeqNoWithoutNoRandom(remoteDataMap.get("serialNo")))
                    .fundCode(fundCode)
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(now)
                    .updateTime(now)
                    .build());
        }
        return result;
    }

    private void processCustShareInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo) {
        try {
            CscAppSecretDTO cscAppSecretDTO = getCscAppSecretDTO(tenant);
            String apiKey = cscAppSecretDTO.getApiKey();
            String apiSecret = cscAppSecretDTO.getApiSecret();
            String encryptKey = cscAppSecretDTO.getEncryptKey();
            List<CustShareInfoEntity> entityList = new ArrayList<>();
            int reqNum = 300;
            int reqPageno = 1;
            Boolean flag = true;
            while (flag) {
                Map<String, Object> bodyParams = new HashMap<>();
                bodyParams.put("reqNum", reqNum);
                bodyParams.put("reqPageno", reqPageno);
                log.info("CustShareInfo入参信息：" + JSON.toJSONString(bodyParams));
                //对入参body进行加密，第二个参数代表加密类型，1代表SM4加密，2代表blowfish加密。
                String body = SM4Util.encryptECB(JsonUtil.toJsonString(bodyParams), encryptKey);
                //拼接url
                String url = UrlConstant.ERP_URL + CSCConstants.CUST_SHARE_INFO_API;
                //传入url和body，调用httpClient请求返回结果hah
                String result = TestHttpUtil.callNoAuthFunc(url, null, body, true, true, apiSecret, apiKey);
                //解密result
                Map<String, Object> resultMap = JsonUtil.toMap(SM4Util.decryptECB(result, encryptKey));
                if (!"0000".equals(resultMap.get("retCode"))) {
                    log.info("custShareInfo接口报错：" + JSON.toJSONString(resultMap.get("retMsg")));
                    Map<String, Object> result1 = new HashMap<>();
                    Object obj = resultMap.get("retMsg");
                    result1.put("data", obj);
                    pullDataFailureLogService.saveErrorData(tenant.getTenantName(), result1);
                    return;
                }
                saveInvokeRecord(tenant, trustNo, CSCConstants.CUST_SHARE_INFO_API, "", bodyParams, resultMap);
                Map<String, Object> data = JsonUtil.toMap(JsonUtil.toJsonString(resultMap.get("data")));
                List<JSONObject> result2 = (List<JSONObject>) data.get("result");
                Integer totalCount = (Integer) data.get("totalCount");
                if (totalCount == null) {
                    totalCount = 0;
                }
                if (reqNum * reqPageno > totalCount) {
                    flag = false;
                }
                if (!CollectionUtils.isEmpty(result2)) {
                    //封装成标准表的对象
                    List<CustShareInfoEntity> custShareInfoEntities = getCustShareInfo(tenant, result2, trustNo);
                    entityList.addAll(custShareInfoEntities);
                }
                reqPageno++;
            }
            custShareInfoService.saveData(null, entityList);
        } catch (Exception e) {
            log.error("custShareInfoData:", e);
            //todo 处理失败
//            pullDataFailureLogService.saveErrorData(tenant.getTenantName(),  PullDataFailureUtil.createErrorMap(trustNo, GuosenConstants.AMAC_CODE_QUERY_LIST_API, null, "appId=" + apiKey, e.getMessage()));
        }
    }

    private List<CustShareInfoEntity> getCustShareInfo(TenantEscrowAuthorizationInfoDto tenant, List<JSONObject> remoteDatas, String trustNo) {
        //1、获取字典表数据
        Map<String, String> serviceDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.SELLER_SERVICE, "中信建投");
//        Map<String, String> fundTypeDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.FUND_TYPE_SERVICE, trustNo);
        Map<String, String> dividendDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.DIVIDEND_WAY_SERVICE, trustNo);

        //2、封装数据
        List<CustShareInfoEntity> result = new ArrayList<>();
        Map<String, String> remoteDataMap;
        Date now = new Date();
        String s = JSONObject.toJSONString(remoteDatas);
        List<JSONObject> datas = JSONObject.parseArray(s, JSONObject.class);
        for (JSONObject remoteData : datas) {
            remoteDataMap = JSONObject.toJavaObject(remoteData, Map.class);

            String agencyNo = remoteDataMap.get("agencyNo");
            String agencyNoValue = MatchDataDictionaryKeyUtil.getKey(serviceDir, agencyNo);
            log.info("getCustShareInfo agencyNo" + agencyNo + " agencyNoValue" + agencyNoValue);

            String agencyName = sellerService.queryAgencyName("中信建投", agencyNo);
            String fundCode = fundInfoService.getFundCodeByInnerFundCode(remoteDataMap.get("fundCode"), trustNo);
            log.info("getFundCodeByInnerFundCode from " + remoteDataMap.get("fundCode") + "to " + fundCode);
            BigDecimal shareRatio = new BigDecimal(remoteDataMap.get("shareRatio") == null ? "0" : NumberUtil.parsePercent(remoteDataMap.get("shareRatio").replace(",", ""))).setScale(4, BigDecimal.ROUND_HALF_UP);
            //处理updateDate
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String updateDate = null;
            if (!StringUtils.isEmpty(remoteDataMap.get("lastModify"))) {
                try {
                    Date parse = sdf.parse(remoteDataMap.get("lastModify"));
                    updateDate = sdf1.format(parse);
                } catch (ParseException e) {
                    e.printStackTrace();
                    log.error("时间转化失败！", e);
                }
            }
            result.add(CustShareInfoEntity.builder()
                    .innerFundCode(remoteDataMap.get("fundCode"))
                    .fundName(remoteDataMap.get("fundName"))
                    .fundAcco(remoteDataMap.get("fundAcco"))
                    .tradeAcco(remoteDataMap.get("tradeAcco"))
                    .agencyNo(agencyNoValue)
                    .agencyName(agencyName)
                    .enableShares(new BigDecimal(remoteDataMap.get("enableShares") == null ? "0" : remoteDataMap.get("enableShares").replace(",", "")).setScale(2))
                    .lastHoldShares(new BigDecimal(remoteDataMap.get("realShares") == null ? "0" : remoteDataMap.get("realShares").replace(",", "")).setScale(2))
                    .shareRatio(BigDecimalUtil.str2BigDecimal(remoteDataMap.get("shareRatio"), 4))
                    .netValueDate(remoteDataMap.get("busiDate"))
                    .frozenShares(new BigDecimal(remoteDataMap.get("frozenShares") == null ? "0" : remoteDataMap.get("frozenShares").replace(",", "")).setScale(2))
                    .bonusMethod(MatchDataDictionaryKeyUtil.getKey(dividendDir, remoteDataMap.get("bonusType")))
                    .income(new BigDecimal(remoteDataMap.get("income") == null ? "0" : remoteDataMap.get("income").replace(",", "")).setScale(2))
                    .updateDate(updateDate)
                    .fundCode(fundCode)
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(now)
                    .updateTime(now)
                    .build());
        }
        return result;
    }

    private void processFundNetValueInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo, int loopTime) {
        CscAppSecretDTO cscAppSecretDTO = getCscAppSecretDTO(tenant);
        String apiKey = cscAppSecretDTO.getApiKey();
        String apiSecret = cscAppSecretDTO.getApiSecret();
        String encryptKey = cscAppSecretDTO.getEncryptKey();
        String startDate;
        String endDate;
        LocalDate localDate = LocalDate.now();
        LocalDate lastMonth;
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        endDate = dateTimeFormatter.format(localDate);
        for (int i = 0; i < loopTime; i++) {
            lastMonth = localDate.minusMonths(1);
            startDate = dateTimeFormatter.format(lastMonth);
            String finalStartDate = startDate;
            String finalEndDate = endDate;
            try {
                //1、封装请求参数
                HashMap<String, Object> params = new HashMap<>();
                int reqNum = 300;
                int reqPageno = 1;

                //2、获取远端数据
                boolean flag = true;
                while (flag) {
                    params.put("reqNum", reqNum);
                    params.put("reqPageno", reqPageno);
                    params.put("netDateBegin", finalStartDate);
                    params.put("netDateEnd", finalEndDate);
                    //对入参body进行加密，第二个参数代表加密类型，1代表SM4加密，2代表blowfish加密。
                    String body = SM4Util.encryptECB(JsonUtil.toJsonString(params), encryptKey);
                    //拼接url
                    String url = UrlConstant.ERP_URL + CSCConstants.FUND_NET_VALUE_INFO_API;
                    //传入url和body，调用httpClient请求返回结果hah
                    String result = TestHttpUtil.callNoAuthFunc(url, null, body, true, true, apiSecret, apiKey);
                    //解密result
                    Map<String, Object> resultMap = JsonUtil.toMap(SM4Util.decryptECB(result, encryptKey));
                    if ("0000".equals(resultMap.get("retCode"))) {
                        saveInvokeRecord(tenant, trustNo, CSCConstants.FUND_NET_VALUE_INFO_API, "", params, resultMap);
                        Map<String, Object> data = JsonUtil.toMap(JsonUtil.toJsonString(resultMap.get("data")));
                        List<JSONObject> result2 = (List<JSONObject>) data.get("result");
                        Integer totalCount = (Integer) data.get("totalCount");
                        if (reqNum * reqPageno > totalCount) {
                            flag = false;
                        }
                        if (!CollectionUtils.isEmpty(result2)) {
                            //3、封装成标准表的对象 //
                            List<FundNetValueInfoEntity> entities = getFundNetValInfo(tenant, result2, trustNo);
                            //4、调用 basicservice 的保存数据接口
                            fundNetValueInfoService.saveData(null, entities);
                        }
                        reqPageno++;
                    } else {
                        log.info("FundNetValueInfo接口报错：" + JSON.toJSONString(resultMap.get("retMsg")));
                        Map<String, Object> result1 = new HashMap<>();
                        Object obj = resultMap.get("retMsg");
                        result1.put("data", obj);
                        pullDataFailureLogService.saveErrorData(tenant.getTenantName(), result1);
                        return;
                    }
                }
            } catch (Exception e) {
                log.error("processFundNetValueInfoData:", e);
            }
            // TODO: 2022/1/13 加一个处理失败的日志统计表
            localDate = lastMonth;
            endDate = startDate;
        }
    }

    private List<FundNetValueInfoEntity> getFundNetValInfo(TenantEscrowAuthorizationInfoDto tenant, List<JSONObject> remoteDatas, String trustNo) {
        //1、获取字典表数据
        Map<String, String> seviceModelDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.SERVICE_MODEL_SERVICE, trustNo);
//        Map<String, String> fundTypeDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.FUND_TYPE_SERVICE, trustNo);
        Map<String, String> fundOperationDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.FUND_OPERATION_FORM_SERVICE, trustNo);


        //2、封装数据
        List<FundNetValueInfoEntity> result = new ArrayList<>();
        Map<String, String> remoteDataMap;
        Date now = new Date();
        String s = JSONObject.toJSONString(remoteDatas);
        List<JSONObject> datas = JSONObject.parseArray(s, JSONObject.class);
        for (JSONObject remoteData : datas) {
            remoteDataMap = JSONObject.toJavaObject(remoteData, Map.class);
            String fundLevel = remoteDataMap.get("fundLevel");
            if (StringUtils.isNotBlank(fundLevel) && fundLevel.equals("0")) {
                fundLevel = null;
            } else {
                fundLevel = "2";
            }
            String fundCode = fundInfoService.getFundCodeByInnerFundCode(remoteDataMap.get("fundCode"), trustNo);
            log.info("getFundCodeByInnerFundCode from " + remoteDataMap.get("fundCode") + "to " + fundCode);

            FundNetValueInfoEntity build = FundNetValueInfoEntity.builder()
                    .netValueDate(remoteDataMap.get("netDate"))
                    .innerFundCode(remoteDataMap.get("fundCode"))
                    .fundName(remoteDataMap.get("fundName"))
                    .shares(new BigDecimal(remoteDataMap.get("assetShares") == null ? "0" : remoteDataMap.get("assetShares").replace(",", "")).setScale(2))
                    .totalAsset(new BigDecimal(remoteDataMap.get("assetTotal") == null ? "0" : remoteDataMap.get("assetTotal").replace(",", "")).setScale(2))
                    .assetValue(new BigDecimal(remoteDataMap.get("assetNet") == null ? "0" : remoteDataMap.get("assetNet").replace(",", "")).setScale(2))
                    .netValue(new BigDecimal(remoteDataMap.get("netAssetVal") == null ? "0" : remoteDataMap.get("netAssetVal").replace(",", "")).setScale(4))
                    .totalNetValue(new BigDecimal(remoteDataMap.get("totalAssetVal") == null ? "0" : remoteDataMap.get("totalAssetVal").replace(",", "")).setScale(4))
                    .ettFundIncome(new BigDecimal(remoteDataMap.get("ettFundIncome") == null ? "0" : remoteDataMap.get("ettFundIncome").replace(",", "")).setScale(2))
                    .sevenDayRate(BigDecimalUtil.str2BigDecimal(remoteDataMap.get("sevenDayRate"), 4))
                    .fundLevel(fundLevel)
                    .fundCode(fundCode)
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(now)
                    .updateTime(now)
                    .build();

            log.info("fundNetValue标准表结果：" + JSON.toJSONString(build));
            result.add(build);
        }
        return result;
    }

    private void processInvestorInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo) {
        try {
            CscAppSecretDTO cscAppSecretDTO = getCscAppSecretDTO(tenant);
            String apiKey = cscAppSecretDTO.getApiKey();
            String apiSecret = cscAppSecretDTO.getApiSecret();
            String encryptKey = cscAppSecretDTO.getEncryptKey();
            int reqNum = 300;
            int reqPageno = 1;
            Boolean flag = true;
            while (flag) {
                Map<String, Object> bodyParams = new HashMap<>();
                bodyParams.put("reqNum", reqNum);
                bodyParams.put("reqPageno", reqPageno);
                //对入参body进行加密，第二个参数代表加密类型，1代表SM4加密，2代表blowfish加密。
                String body = SM4Util.encryptECB(JsonUtil.toJsonString(bodyParams), encryptKey);
                //拼接url
                String url = UrlConstant.ERP_URL + CSCConstants.INVESTOR_INFO_API;
                //传入url和body，调用httpClient请求返回结果hah
                String result = TestHttpUtil.callNoAuthFunc(url, null, body, true, true, apiSecret, apiKey);
                //解密result
                Map<String, Object> resultMap = JsonUtil.toMap(SM4Util.decryptECB(result, encryptKey));
                if (!"0000".equals(resultMap.get("retCode"))) {
                    log.info("账户余额接口报错：" + JSON.toJSONString(resultMap.get("retMsg")));
                    Map<String, Object> result1 = new HashMap<>();
                    Object obj = resultMap.get("retMsg");
                    result1.put("data", obj);
                    pullDataFailureLogService.saveErrorData(tenant.getTenantName(), result1);
                    return;
                }
                saveInvokeRecord(tenant, trustNo, CSCConstants.INVESTOR_INFO_API, "", bodyParams, resultMap);
                Map<String, Object> data = JsonUtil.toMap(JsonUtil.toJsonString(resultMap.get("data")));
                List<JSONObject> result2 = (List<JSONObject>) data.get("result");
                Integer totalCount = (Integer) data.get("totalCount");
                if (reqNum * reqPageno > totalCount) {
                    flag = false;
                }
                if (!CollectionUtils.isEmpty(result2)) {
                    //封装成标准表的对象
                    List<InvestorInfoEntity> investorInfoEntities = getInvestorInfo(tenant, result2, trustNo);
                    investorInfoService.saveData(null, investorInfoEntities);
                    //托管户封装成标准表的对象
                    List<InvestorBankInfoEntity> investorBankInfoEntities = getInvestorBankInfo(tenant, result2, trustNo);
                    investorBankInfoService.saveData(null, investorBankInfoEntities);
                }

                reqPageno++;
            }
        } catch (Exception e) {
            log.error("investorInfoData:", e);
            //todo 处理失败
//            pullDataFailureLogService.saveErrorData(tenant.getTenantName(),  PullDataFailureUtil.createErrorMap(trustNo, GuosenConstants.AMAC_CODE_QUERY_LIST_API, null, "appId=" + apiKey, e.getMessage()));
        }
    }

    private List<InvestorBankInfoEntity> getInvestorBankInfo(TenantEscrowAuthorizationInfoDto tenant, List<JSONObject> remoteDatas, String trustNo) {
        //1、获取字典表数据
        Map<String, String> bankCodeDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.BANK_CODE_SERVICE, "中信建投TA");
        //2、封装数据
        List<InvestorBankInfoEntity> result = new ArrayList<>();
        Map<String, String> remoteDataMap;
        Date now = new Date();
        String s = JSONObject.toJSONString(remoteDatas);
        List<JSONObject> datas = JSONObject.parseArray(s, JSONObject.class);
        for (JSONObject remoteData : datas) {
            remoteDataMap = JSONObject.toJavaObject(remoteData, Map.class);
            if (remoteDataMap.get("bankAcco") == null) {
                log.error("bankAcco不应为空" + remoteDataMap.get("bankAcco"));
                continue;
            }
            String bankNo = MatchDataDictionaryKeyUtil.getKey(bankCodeDir, remoteDataMap.get("bankNo"));
            log.info("getInvestorBankInfo:bankNo为" + remoteDataMap.get("bankNo") + " 转义后bankCode为" + bankNo);
            result.add(InvestorBankInfoEntity.builder()
                    .fundAcco(remoteDataMap.get("fundAcco"))
                    .tradeAcco(remoteDataMap.get("tradeAcco"))
                    .bankCode(bankNo)
                    .bankNo(remoteDataMap.get("bankAcco"))
                    .branchBankName(remoteDataMap.get("openBankName"))
                    .nameInBank(remoteDataMap.get("nameInBank"))
                    .bankNoType("银行账号")
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(now)
                    .updateTime(now)
                    .build());
        }
        return result;
    }

    private List<InvestorInfoEntity> getInvestorInfo(TenantEscrowAuthorizationInfoDto tenant, List<JSONObject> remoteDatas, String trustNo) {
        //1、获取字典表数据
        Map<String, String> seviceModelDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.SERVICE_MODEL_SERVICE, trustNo);
//        Map<String, String> fundTypeDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.FUND_TYPE_SERVICE, trustNo);
        Map<String, String> fundOperationDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.FUND_OPERATION_FORM_SERVICE, trustNo);
        Map<String, String> custTypeCsdcDic = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.CUST_TYPE_CSDC_SERVICE, trustNo);
        Map<String, Map<String, String>> identityTypeCsdcDic = certificateCsdcService.queryCertificateWithDetail(trustNo);

        //2、封装数据
        List<InvestorInfoEntity> result = new ArrayList<>();
        Map<String, String> remoteDataMap;
        Date now = new Date();
        String s = JSONObject.toJSONString(remoteDatas);
        List<JSONObject> datas = JSONObject.parseArray(s, JSONObject.class);
        for (JSONObject remoteData : datas) {
            remoteDataMap = JSONObject.toJavaObject(remoteData, Map.class);
            String key = MatchDataDictionaryKeyUtil.getKey(custTypeCsdcDic, remoteDataMap.get("custType"));

            String certiType = remoteDataMap.get("certiType");
            String identityType = MatchDataDictionaryKeyUtil.getKey(key, identityTypeCsdcDic, certiType);
            log.info("getInvestorInfo的原值certiType为" + certiType + " 映射值identityType为" + identityType);
            log.info("custType__certiType__identityType" + certiType + " " + key + " " + identityType);

            result.add(InvestorInfoEntity.builder()
                    .custName(remoteDataMap.get("custName"))
                    .fundAcco(remoteDataMap.get("fundAcco"))
                    .custType(key)
                    .identityType(identityType)
                    .identityNo(remoteDataMap.get("certiNo"))
                    .address(remoteDataMap.get("address"))
                    .mobileNo(remoteDataMap.get("tel"))
                    .zipCode(remoteDataMap.get("zipCode"))
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(now)
                    .updateTime(now)
                    .build());
        }
        return result;
    }

    private void processAccountInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo) {
        try {
            CscAppSecretDTO cscAppSecretDTO = getCscAppSecretDTO(tenant);
            String apiKey = cscAppSecretDTO.getApiKey();
            String apiSecret = cscAppSecretDTO.getApiSecret();
            String encryptKey = cscAppSecretDTO.getEncryptKey();
            int reqNum = 300;
            int reqPageno = 1;
            Boolean flag = true;
            while (flag) {
                Map<String, Object> bodyParams = new HashMap<>();
                bodyParams.put("reqNum", reqNum);
                bodyParams.put("reqPageno", reqPageno);
                log.info("accountInfo入参：" + JSON.toJSONString(bodyParams));
                //对入参body进行加密，第二个参数代表加密类型，1代表SM4加密，2代表blowfish加密。
                String body = SM4Util.encryptECB(JsonUtil.toJsonString(bodyParams), encryptKey);
                //拼接url
                String url = UrlConstant.ERP_URL + CSCConstants.ACCOUNT_INFO_API;
                //传入url和body，调用httpClient请求返回结果hah
                String result = TestHttpUtil.callNoAuthFunc(url, null, body, true, true, apiSecret, apiKey);
                //解密result
                Map<String, Object> resultMap = JsonUtil.toMap(SM4Util.decryptECB(result, encryptKey));
                log.info("resultMap结果：" + JSON.toJSONString(resultMap));
                if (!"0000".equals(resultMap.get("retCode"))) {
                    log.info("账户余额接口报错：" + JSON.toJSONString(resultMap.get("retMsg")));
                    Map<String, Object> result1 = new HashMap<>();
                    Object obj = resultMap.get("retMsg");
                    result1.put("data", obj);
                    pullDataFailureLogService.saveErrorData(tenant.getTenantName(), result1);
                    return;
                }
                saveInvokeRecord(tenant, trustNo, CSCConstants.ACCOUNT_INFO_API, "", bodyParams, resultMap);
                Map<String, Object> data = JsonUtil.toMap(JsonUtil.toJsonString(resultMap.get("data")));
                List<JSONObject> result2 = (List<JSONObject>) data.get("result");
                Integer totalCount = (Integer) data.get("totalCount");
                if (reqNum * reqPageno > totalCount) {
                    flag = false;
                }
                if (!CollectionUtils.isEmpty(result2)) {
                    //封装成标准表的对象
                    List<AccountInfoEntity> accountInfo = getAccountInfo(tenant, result2, trustNo);
                    accountInfoService.saveData(null, accountInfo);
                    //托管户封装成标准表的对象
                    List<TgAccountBalanceInfoEntity> entities = getTgAccountBalanceInfo(tenant, result2, trustNo);
                    tgAccountBalanceInfoService.saveData(null, entities);

                    //募集户封装成标准表的对象
                    List<MjAccountBalanceInfoEntity> entitiesMj = getMJAccountBalanceInfo(tenant, result2, trustNo);
                    mjAccountBalanceInfoService.saveData(null, entitiesMj);
                }
                reqPageno++;
            }
        } catch (Exception e) {
            log.error("accountInfoData保存信息失败:", e);
            //todo 处理失败
//            pullDataFailureLogService.saveErrorData(tenant.getTenantName(),  PullDataFailureUtil.createErrorMap(trustNo, GuosenConstants.AMAC_CODE_QUERY_LIST_API, null, "appId=" + apiKey, e.getMessage()));
        }
    }

    //募集户账户余额
    private List<MjAccountBalanceInfoEntity> getMJAccountBalanceInfo(TenantEscrowAuthorizationInfoDto tenant, List<JSONObject> remoteDatas, String trustNo) {
        //1、获取字典表数据
        Map<String, String> currencyDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.CURRENCY_SERVICE, trustNo);

        //2、封装数据
        List<MjAccountBalanceInfoEntity> result = new ArrayList<>();
        Map<String, String> remoteDataMap;
        Date now = new Date();
        String s = JSONObject.toJSONString(remoteDatas);
        List<JSONObject> datas = JSONObject.parseArray(s, JSONObject.class);
        for (JSONObject remoteData : datas) {
            remoteDataMap = JSONObject.toJavaObject(remoteData, Map.class);
            String accType = remoteDataMap.get("accType");
            log.info("账户类型：" + accType);
            if ("02".equals(accType)) {
                result.add(MjAccountBalanceInfoEntity.builder()
                        .currency(MatchDataDictionaryKeyUtil.getKey(currencyDir, remoteDataMap.get("curType")))
                        .bankAcco(remoteDataMap.get("bankAcco"))
                        .accoBalance(new BigDecimal(remoteDataMap.get("acctBal") == null ? "0" : remoteDataMap.get("acctBal").replace(",", "")).setScale(2))
                        .updateDate(remoteDataMap.get("retTime"))
                        .trustNo(trustNo)
                        .admin(tenant.getTenantName())
                        .createTime(now)
                        .updateTime(now)
                        .build());
            }
        }
        return result;

    }

    //托管户账户余额
    private List<TgAccountBalanceInfoEntity> getTgAccountBalanceInfo(TenantEscrowAuthorizationInfoDto tenant, List<JSONObject> remoteDatas, String trustNo) {
        //1、获取字典表数据
        Map<String, String> currencyDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.CURRENCY_SERVICE, trustNo);
        //2、封装数据
        List<TgAccountBalanceInfoEntity> result = new ArrayList<>();
        Map<String, String> remoteDataMap;
        Date now = new Date();
        String s = JSONObject.toJSONString(remoteDatas);
        List<JSONObject> datas = JSONObject.parseArray(s, JSONObject.class);
        for (JSONObject remoteData : datas) {
            remoteDataMap = JSONObject.toJavaObject(remoteData, Map.class);
            String accType = remoteDataMap.get("accType");
            log.info("账户类型：" + accType);
            if ("04".equals(accType)) {
                result.add(TgAccountBalanceInfoEntity.builder()
                        .currency(MatchDataDictionaryKeyUtil.getKey(currencyDir, remoteDataMap.get("curType")))
                        .bankAcco(remoteDataMap.get("bankAcco"))
                        .accoBalance(new BigDecimal(remoteDataMap.get("acctBal") == null ? "0" : remoteDataMap.get("acctBal").replace(",", "")).setScale(2))
                        .updateDate(remoteDataMap.get("retTime")) //todo 可能格式不对
                        .trustNo(trustNo)
                        .admin(tenant.getTenantName())
                        .createTime(now)
                        .updateTime(now)
                        .build());
            }
        }
        return result;

    }

    private List<AccountInfoEntity> getAccountInfo(TenantEscrowAuthorizationInfoDto tenant, List<JSONObject> remoteDatas, String trustNo) {
        //1、获取字典表数据
        Map<String, String> currencyDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.CURRENCY_SERVICE, trustNo);
        Map<String, String> type = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.ACCOUNT_TYPE_SERVICE, trustNo);
        Map<String, String> code = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.BANK_CODE_SERVICE, "中信建投TA");

        //2、封装数据
        List<AccountInfoEntity> result = new ArrayList<>();
        Map<String, String> remoteDataMap;
        Date now = new Date();
        String s = JSONObject.toJSONString(remoteDatas);
        List<JSONObject> datas = JSONObject.parseArray(s, JSONObject.class);
        for (JSONObject remoteData : datas) {

            remoteDataMap = JSONObject.toJavaObject(remoteData, Map.class);
            result.add(AccountInfoEntity.builder()
                    .currency(MatchDataDictionaryKeyUtil.getKey(currencyDir, remoteDataMap.get("curType")))
                    .innerFundCode(remoteDataMap.get("fundCode"))
                    .fundName(remoteDataMap.get("fundName"))
                    .accoTypeCode(MatchDataDictionaryKeyUtil.getKey(type, remoteDataMap.get("accType")))
                    .bankAcco(remoteDataMap.get("bankAcco"))
                    .nameInBank(remoteDataMap.get("accName"))
                    .bankCode(MatchDataDictionaryKeyUtil.getKey(code, remoteDataMap.get("bankNo")))
                    .branchBankName(remoteDataMap.get("openBankName"))
                    .fundCode(remoteDataMap.get("fundCode"))
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(now)
                    .updateTime(now)
                    .build());
        }
        return result;

    }

    private void processFundInfoData(TenantEscrowAuthorizationInfoDto tenant, String trustNo) {
        try {
            CscAppSecretDTO cscAppSecretDTO = getCscAppSecretDTO(tenant);
            String apiKey = cscAppSecretDTO.getApiKey();
            String apiSecret = cscAppSecretDTO.getApiSecret();
            String encryptKey = cscAppSecretDTO.getEncryptKey();
            List<String> trustNos = accountInfoService.queryFundCodeByTrustNo(trustNo, tenant.getTenantName());
            for (String fundCode : trustNos) {
                Map<String, Object> bodyParams = new HashMap<String, Object>();
                bodyParams.put("fundCode", fundCode);
                //对入参body进行加密，第二个参数代表加密类型，1代表SM4加密，2代表blowfish加密。
                String body = SM4Util.encryptECB(JsonUtil.toJsonString(bodyParams), encryptKey);
                //拼接url
                String url = UrlConstant.ERP_URL + CSCConstants.FUND_INFO_API;
                //传入url和body，调用httpClient请求返回结果hah
                String result = TestHttpUtil.callNoAuthFunc(url, null, body, true, true, apiSecret, apiKey);
                //解密result
                Map<String, Object> resultMap = JsonUtil.toMap(SM4Util.decryptECB(result, encryptKey));
                if (!"0000".equals(resultMap.get("retCode"))) {
                    log.info("产品信息接口报错：" + JSON.toJSONString(resultMap.get("retMsg")));
                    Map<String, Object> result1 = new HashMap<>();
                    result1.put("data", resultMap.get("retMsg"));
                    pullDataFailureLogService.saveErrorData(tenant.getTenantName(), result1);
                    continue;
                }
                saveInvokeRecord(tenant, trustNo, CSCConstants.FUND_INFO_API, "", bodyParams, resultMap);
                Object obj = resultMap.get("data");
                if (!Objects.isNull(obj) && obj instanceof ArrayList) {
                    //Map<String, Object> data = JsonUtil.toMap(JsonUtil.toJsonString());
                    List<JSONObject> remoteData = (List<JSONObject>) resultMap.get("data");
                    List<FundInfoEntity> entities = getFundInfo(tenant, remoteData, trustNo);
                    //如标准表
                    fundInfoService.saveData(null, entities);
                }
            }
        } catch (Exception e) {
            log.error("processFundInfoData:", e);
            //todo 处理失败
//            pullDataFailureLogService.saveErrorData(tenant.getTenantName(),  PullDataFailureUtil.createErrorMap(trustNo, GuosenConstants.AMAC_CODE_QUERY_LIST_API, null, "appId=" + apiKey, e.getMessage()));
        }
    }

    private List<FundInfoEntity> getFundInfo(TenantEscrowAuthorizationInfoDto tenant, List<JSONObject> remoteDatas, String trustNo) {
        //1、获取字典表数据
        Map<String, String> seviceModelDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.SERVICE_MODEL_SERVICE, trustNo);
        Map<String, String> taConfDaysDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.TA_TRANSACTION_CONFIRM_ATION_DAYS_SERVICE, trustNo);
        //Map<String, String> fundTypeDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.FUND_TYPE_SERVICE, trustNo);
        Map<String, String> proDir = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.PRODUCT_STATUS_SERVICE, trustNo);
        //Map<String, String> privateFundType = dataDictionaryBasicService.queryWithDetail(DataDictionaryTypeEnum.PRIVATE_FUND_TYPE_SERVICE, trustNo);

        //2、封装数据
        List<FundInfoEntity> result = new ArrayList<>();
        Map<String, String> remoteDataMap;
        Date now = new Date();
        List<JSONObject> datas = JSONObject.parseArray(JSONObject.toJSONString(remoteDatas), JSONObject.class);
        for (JSONObject remoteData : datas) {
            remoteDataMap = JSONObject.toJavaObject(remoteData, Map.class);
            result.add(FundInfoEntity.builder()
                    .innerFundCode(remoteDataMap.get("fundCode"))
                    .fundCode(remoteDataMap.get("fundCode"))
                    .fundName(remoteDataMap.get("fundName"))
                    .serviceMode(MatchDataDictionaryKeyUtil.getKey(seviceModelDir, remoteDataMap.get("serviceMode")))
                    .fundStatus(MatchDataDictionaryKeyUtil.getKey(proDir, remoteDataMap.get("fundStatus")))
                    .createDate(remoteDataMap.get("establishDate"))
                    .confDays(MatchDataDictionaryKeyUtil.getKey(taConfDaysDir, String.valueOf(remoteDataMap.get("confDays"))))
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .createTime(now)
                    .updateTime(now)
                    .build());
        }
        return result;
    }

    public void saveInvokeRecord(TenantEscrowAuthorizationInfoDto tenant, String trustNo, String invokeType, String headers, Map<String, Object> params, Map<String, Object> invokeResult) {
        Date now = new Date();
        InvokeRecordEntity invokeRecordEntity = InvokeRecordEntity.builder()
                .trustNo(trustNo)
                .admin(tenant.getTenantName())
                .invokeType(invokeType)
                .reqHeader(JSON.toJSONString(headers))
                .reqParam(JSON.toJSONString(params))
                .invokeTime(now)
                .invokeResult(JSON.toJSONString(invokeResult))
                .queryKey(tenant.getTenantName() + "::" + trustNo + "::" + invokeType)
                .createTime(now)
                .updateTime(now)
                .build();
        invokeRecordService.save(invokeRecordEntity);
    }

    private Object getData(String url, String body, TenantEscrowAuthorizationInfoDto tenant, String trustNo) {
        try {
            String result = TestHttpUtil.callNoAuthFunc(url, null, body, true, true, UrlConstant.API_SECRET, UrlConstant.API_KEY);
            log.info("the url is {} ; the params is {} ; the result is {}", url, JSON.toJSONString(body), JSON.toJSONString(result));
            Date date = new Date();
            InvokeRecordEntity invokeRecordEntity = InvokeRecordEntity.builder()
                    .trustNo(trustNo)
                    .admin(tenant.getTenantName())
                    .invokeType(url)
                    .reqHeader(JSON.toJSONString(body))
                    .reqParam(JSON.toJSONString(body))
                    .invokeTime(date)
                    .invokeResult(JSON.toJSONString(result))
                    .queryKey(tenant.getTenantName() + "::" + trustNo + "::" + url)
                    .createTime(date)
                    .updateTime(date)
                    .build();
            invokeRecordService.save(invokeRecordEntity);
            log.info("调用结果: " + JSON.toJSONString(result));
            //解密result
            Map<String, Object> resultMap = JsonUtil.toMap(SM4Util.decryptECB(result, UrlConstant.EncryptKey));

            if (!"0000".equals(resultMap.get("retCode"))) {
                return null;
            }
            Map<String, Object> data = JsonUtil.toMap(JsonUtil.toJsonString(resultMap.get("data")));
            List<JSONObject> result2 = (List<JSONObject>) data.get("result");
            return result2;
        } catch (Exception e) {

        }
        return null;
    }

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

    @Override
    public R updateSingleDataDaily(TenantEscrowAuthorizationInfoDto tenant) {
        log.info("建投托管数据初始化...");
        getUpdateDataFromCsc(tenant, 1); //先都拿1年，客户有需求再增加到3年
        log.info("建投托管数据初始化结束:");
        return R.ok("建投托管数据初始化结束！");
    }

    @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("csc: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:
                    processMJAccountSeqInfoData(tenant, trustNo, loopNum);
                    log.info("管理人{}中信建投募集户流水更新完成!", tenant.getTenantName());
                    //17 托管⼾流⽔表（TGAccount_seq_info）
                    processTGAccountSeqInfoData(tenant, trustNo, loopNum);
                    log.info("管理人{}中信建投托管户流水更新完成!", tenant.getTenantName());
                    break;
            }
        }catch (Exception e){
            log.error("中信建投更新流水表失败!", e);
        }
        return null;
    }

    private void initTenantDataBy305(TenantEscrowAuthorizationInfoDto tenant, String trustNo, Integer loopTime) {
        try {
            log.info("csc: fundOpenInfo初始化开始！");
            //基金费用查询 ( fund_fee_data_info )
            processFundOpenInfoData(tenant, trustNo, loopTime);
            log.info("csc: fundOpenInfo初始化結束！");
        } catch (Exception e) {
            log.error("csc:initTenantDataBy305 is error:", e);
        }
    }

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

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

    @Override
    public R updateSingleData20min(TenantEscrowAuthorizationInfoDto tenant) {
        log.info("建投托管数据每20min跟新...");
        String trustNo = tenant.getTrustNo();
        Integer loopTime = CustodyContants.UPDATE_BY_MONTH_DAILY_LOOP_TIME;
        //15 资金账户基本信息表 account_info，16 托管⼾银⾏账⼾余额信息表（TGAccount_balance_info,MJAccount_balance_info）
        processAccountInfoData(tenant, trustNo);
        //19 募集⼾流⽔表（MJAccount_seq_info）
        processMJAccountSeqInfoData(tenant, trustNo, loopTime);
        //17 托管⼾流⽔表（TGAccount_seq_info）
        processTGAccountSeqInfoData(tenant, trustNo, loopTime);
        log.info("建投托管数据每20min跟新结束:");
        return R.ok("建投托管数据每20min跟新完成");
    }

    @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) {
        try {
            log.info("建投每8点、12点、20点更新数据开始！");
            String trustNo = tenant.getTrustNo();
            int loopTime = CustodyContants.UPDATE_BY_MONTH_DAILY_LOOP_TIME;
            //3 基金净值信息表（fund_net_value_info）
            processFundNetValueInfoData(tenant, trustNo, loopTime);
            log.info("建投每8点、12点、20点更新数据结束！");
        }catch(Exception e){
            log.error("建投每8点、12点、20点更新数据异常！", e);
        }
        return R.ok("建投每8点、12点、20点更新数据完成！");
    }

    @Override
    public DubboResult updateMJBalanceData(TenantEscrowAuthorizationInfoDto tenant) {
        try {
            String trustNo = tenant.getTrustNo();
            // 更新资金账户基本信息表 account_info，托管户、募集户余额信息表（TGAccount_balance_info,MJAccount_balance_info）
            processAccountInfoData(tenant, trustNo);
            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 trustNo = tenant.getTrustNo();
            // 募集户流水表（MJAccount_seq_info）
            processMJAccountSeqInfoData(tenant, trustNo, CustodyContants.UPDATE_BY_MONTH_DAILY_LOOP_TIME);
            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 trustNo = tenant.getTrustNo();
            // 更新资金账户基本信息表 account_info，托管⼾银⾏账⼾余额信息表（TGAccount_balance_info,MJAccount_balance_info）
            processAccountInfoData(tenant, trustNo);
            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 trustNo = tenant.getTrustNo();
            // 托管户流水表（TGAccount_seq_info）
            processTGAccountSeqInfoData(tenant, trustNo, CustodyContants.UPDATE_BY_MONTH_DAILY_LOOP_TIME);
            return DubboResult.newSuccess();
        } catch (Exception e) {
            log.error("手动更新托管户流水失败", e);
            return DubboResult.newFailure(DubboResult.SERVER_EXCEPTION, "手动更新托管户流水失败" + e.getMessage());
        }
    }
}
