package com.simuwang.manage.service.competition; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.map.MapUtil; import com.simuwang.base.common.conts.DateConst; import com.simuwang.base.common.util.NavDataUtil; import com.simuwang.base.mapper.*; import com.simuwang.base.pojo.dos.*; import com.simuwang.base.pojo.dto.FundNavDataDTO; import com.simuwang.base.pojo.dto.FundNavDeletionDTO; import com.simuwang.base.pojo.dto.TradeDateDTO; import com.simuwang.base.pojo.dto.competition.CompetitionBaseResultDTO; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Service public class FundNavService { private final NavMapper navMapper; private final FundInfoMapper fundInfoMapper; private final AssetMapper assetMapper; private final DeletionInfoMapper deletionInfoMapper; private final TradeDateMapper tradeDateMapper; private final CompetitionFactory competitionFactory; public FundNavService(NavMapper navMapper, FundInfoMapper fundInfoMapper, AssetMapper assetMapper, DeletionInfoMapper deletionInfoMapper, TradeDateMapper tradeDateMapper, CompetitionFactory competitionFactory) { this.navMapper = navMapper; this.fundInfoMapper = fundInfoMapper; this.assetMapper = assetMapper; this.deletionInfoMapper = deletionInfoMapper; this.tradeDateMapper = tradeDateMapper; this.competitionFactory = competitionFactory; } public List getFungNavData(Integer competitionId) { List navDataDTOList = CollUtil.newArrayList(); List navDOList = navMapper.queryAllNav(competitionId); if (CollUtil.isEmpty(navDOList)) { return navDataDTOList; } // 过滤出周频的净值点 String toDay = DateUtil.format(new Date(), DateConst.YYYY_MM_DD); List tradeDateDOList = tradeDateMapper.listAllTradeDate(toDay); navDOList = NavDataUtil.filterWeekFrequencyNav(navDOList, tradeDateDOList); List fundIdList = navDOList.stream().map(NavDO::getFundId).distinct().toList(); List fundInfoCompanyNameList = fundInfoMapper.queryFundAndTrustByFundId(competitionId); Map fundIdCompanyNameMap = fundInfoCompanyNameList.stream().collect(Collectors.toMap(FundAndCompanyInfoDO::getFundId, v -> v)); List assetDOList = assetMapper.queryAssetByFundId(fundIdList); Map> fundIdAssetMap = MapUtil.newHashMap(); if (CollUtil.isNotEmpty(assetDOList)) { fundIdAssetMap = assetDOList.stream().collect(Collectors.groupingBy(AssetDO::getFundId)); } Map> fundIdNavMap = navDOList.stream().collect(Collectors.groupingBy(NavDO::getFundId)); for (Map.Entry> fundIdNavEntry : fundIdNavMap.entrySet()) { String fundId = fundIdNavEntry.getKey(); List fundNavDoList = fundIdNavEntry.getValue(); List fundAssetDoList = fundIdAssetMap.get(fundId); FundAndCompanyInfoDO fundInfoDO = fundIdCompanyNameMap.get(fundId); List fundNavDataDTOList = buildFundNavDataDTO(fundInfoDO, fundNavDoList, fundAssetDoList); navDataDTOList.addAll(fundNavDataDTOList); } return navDataDTOList; } public List getFundNavDeletion(Integer competitionId, String endDate) { List navDeletionDTOList = CollUtil.newArrayList(); // 缺失类型-1对应全部,1-净值缺失,2-对应规模缺失,3-对应分红缺失,5-估值缺失 List deletionInfoDOList = deletionInfoMapper.getFundNavDeletionNew(1, competitionId, endDate); if (CollUtil.isEmpty(deletionInfoDOList)) { return navDeletionDTOList; } Map> fundIdDeletionInfoMap = deletionInfoDOList.stream().collect(Collectors.groupingBy(FundDeletionInfoDO::getFundId)); // 基金信息和对应的管理人信息 List fundInfoCompanyNameList = fundInfoMapper.queryFundAndTrustByFundId(competitionId); if (CollUtil.isEmpty(fundInfoCompanyNameList)) { return navDeletionDTOList; } // 得到存在基金完整的基金id List allFundIdList = navMapper.getAllFundId(); // 得到基金净值缺失的基金Id List deletionFundIdList = getDeletionFundId(fundInfoCompanyNameList, fundIdDeletionInfoMap); List notDeletionFundIdList = allFundIdList.stream().filter(e -> !deletionFundIdList.contains(e)).toList(); // 过滤掉净值没有缺失的基金Id fundInfoCompanyNameList = fundInfoCompanyNameList.stream().filter(e -> !notDeletionFundIdList.contains(e.getFundId())).toList(); for (FundAndCompanyInfoDO fundAndCompanyInfoDO : fundInfoCompanyNameList) { String fundId = fundAndCompanyInfoDO.getFundId(); String entryDate = DateUtil.format(fundAndCompanyInfoDO.getEntryDate(), DateConst.YYYY_MM_DD); // 获取净值日期所在年和所在周 Map tradeDateDoMap = getYearAndWeekOfDate(entryDate, endDate); List fundDeletionInfoDOList = fundIdDeletionInfoMap.get(fundId); if (CollUtil.isNotEmpty(fundDeletionInfoDOList)) { fundDeletionInfoDOList = fundDeletionInfoDOList.stream().filter(e -> e.getDeletionDate().compareTo(entryDate) >= 0).toList(); } List fundNavDataDTOList = buildFundNavDeletionDTO(fundAndCompanyInfoDO, fundDeletionInfoDOList, tradeDateDoMap); navDeletionDTOList.addAll(fundNavDataDTOList); } return navDeletionDTOList; } private List getDeletionFundId(List fundInfoCompanyNameList, Map> fundIdDeletionInfoMap) { List deletionFundIdList = CollUtil.newArrayList(); for (FundAndCompanyInfoDO fundAndCompanyInfoDO : fundInfoCompanyNameList) { String fundId = fundAndCompanyInfoDO.getFundId(); String entryDate = DateUtil.format(fundAndCompanyInfoDO.getEntryDate(), DateConst.YYYY_MM_DD); List fundDeletionInfoDOList = fundIdDeletionInfoMap.get(fundId); if (CollUtil.isEmpty(fundDeletionInfoDOList)) { continue; } long count = fundDeletionInfoDOList.stream().filter(e -> e.getDeletionDate().compareTo(entryDate) >= 0).count(); if (count != 0) { deletionFundIdList.add(fundId); } } return deletionFundIdList; } public List getCompetitionResult(Integer competitionId, String period) { List dataList = CollUtil.newArrayList(); AbstractCompetitionResultService competitionResult = competitionFactory.getInstance(competitionId); if (competitionResult == null) { return dataList; } return competitionResult.getCompetitionResult(competitionId, period); } private List buildFundNavDeletionDTO(FundAndCompanyInfoDO fundAndCompanyInfoDO, List fundDeletionInfoDOList, Map tradeDateDoMap) { String fundName = fundAndCompanyInfoDO.getFundName(); String trustName = fundAndCompanyInfoDO.getCompanyName(); String trustRegisterNumber = fundAndCompanyInfoDO.getCompanyRegisterNumber(); String registerNumber = fundAndCompanyInfoDO.getRegisterNumber(); String fundId = fundAndCompanyInfoDO.getFundId(); // 净值缺失表中无该基金的数据 -> 该基金为缺失全部净值 if (CollUtil.isEmpty(fundDeletionInfoDOList)) { List navDeletionDTOList = CollUtil.newArrayList(); tradeDateDoMap.forEach((k, v) -> { FundNavDeletionDTO fundNavDeletionDTO = new FundNavDeletionDTO(); fundNavDeletionDTO.setTrustName(trustName); fundNavDeletionDTO.setTrustRegisterNumber(trustRegisterNumber); fundNavDeletionDTO.setFundId(fundId); fundNavDeletionDTO.setFundName(fundName); fundNavDeletionDTO.setRegisterNumber(registerNumber); fundNavDeletionDTO.setYear(v != null ? v.getYear() + v.getWeek() : null); fundNavDeletionDTO.setWeek(v != null ? String.valueOf(v.getWeek()) : null); // 第1周(2022-12-26至2022-12-30) String date = v != null ? v.getFirstDate() + "至" + v.getLastDate() : null; fundNavDeletionDTO.setCompetitionDate(date); fundNavDeletionDTO.setDate(k); navDeletionDTOList.add(fundNavDeletionDTO); }); navDeletionDTOList.sort(Comparator.comparing(FundNavDeletionDTO::getFundName).thenComparing(FundNavDeletionDTO::getWeek)); return navDeletionDTOList; } return fundDeletionInfoDOList.stream().map(e -> { FundNavDeletionDTO fundNavDeletionDTO = new FundNavDeletionDTO(); fundNavDeletionDTO.setTrustName(trustName); fundNavDeletionDTO.setTrustRegisterNumber(trustRegisterNumber); fundNavDeletionDTO.setFundId(fundId); fundNavDeletionDTO.setFundName(fundName); fundNavDeletionDTO.setRegisterNumber(registerNumber); TradeDateDTO tradeDateDTO = tradeDateDoMap.get(e.getDeletionDate()); fundNavDeletionDTO.setYear(tradeDateDTO != null ? tradeDateDTO.getYear() + tradeDateDTO.getWeek() : null); fundNavDeletionDTO.setWeek(tradeDateDTO != null ? String.valueOf(tradeDateDTO.getWeek()) : null); // 第1周(2022-12-26至2022-12-30) String date = tradeDateDTO != null ? tradeDateDTO.getFirstDate() + "至" + tradeDateDTO.getLastDate() : null; fundNavDeletionDTO.setCompetitionDate(date); fundNavDeletionDTO.setDate(e.getDeletionDate()); return fundNavDeletionDTO; }).sorted(Comparator.comparing(FundNavDeletionDTO::getFundName).thenComparing(FundNavDeletionDTO::getWeek)).toList(); } private List buildFundNavDataDTO(FundAndCompanyInfoDO fundInfoDO, List fundNavDoList, List fundAssetDoList) { String fundName = fundInfoDO.getFundName(); String registerNumber = fundInfoDO.getRegisterNumber(); String trustName = fundInfoDO.getCompanyName(); String trustRegisterNumber = fundInfoDO.getCompanyRegisterNumber(); Map priceDateAssetMap = MapUtil.newHashMap(); if (CollUtil.isNotEmpty(fundAssetDoList)) { priceDateAssetMap = fundAssetDoList.stream().collect(Collectors.toMap(k -> DateUtil.format(k.getPriceDate(), DateConst.YYYY_MM_DD), AssetDO::getAssetNet)); } Map finalPriceDateAssetMap = priceDateAssetMap; return fundNavDoList.stream().map(e -> { FundNavDataDTO fundNavDataDTO = new FundNavDataDTO(); fundNavDataDTO.setTrustName(trustName); fundNavDataDTO.setTrustRegisterNumber(trustRegisterNumber); fundNavDataDTO.setFundId(e.getFundId()); fundNavDataDTO.setFundName(fundName); fundNavDataDTO.setRegisterNumber(registerNumber); String priceDate = e.getPriceDate() != null ? DateUtil.format(e.getPriceDate(), DateConst.YYYY_MM_DD) : null; fundNavDataDTO.setPriceDate(priceDate); fundNavDataDTO.setNav(e.getNav() != null ? String.valueOf(e.getNav()) : null); fundNavDataDTO.setCumulativeNavWithdrawal(e.getCumulativeNavWithdrawal() != null ? String.valueOf(e.getCumulativeNavWithdrawal()) : null); BigDecimal asset = finalPriceDateAssetMap.get(priceDate) != null ? finalPriceDateAssetMap.get(priceDate).setScale(2, RoundingMode.HALF_UP) : null; fundNavDataDTO.setAsset(asset != null ? String.valueOf(asset) : null); return fundNavDataDTO; }).sorted(Comparator.comparing(FundNavDataDTO::getFundName).thenComparing(FundNavDataDTO::getPriceDate)).toList(); } private Map getYearAndWeekOfDate(String startDate, String endDate) { Map tradeDateDoMap = MapUtil.newHashMap(); List tradeDateDOList = tradeDateMapper.selectTradeDate(startDate, endDate); if (CollUtil.isEmpty(tradeDateDOList)) { return tradeDateDoMap; } List yearWeekList = tradeDateDOList.stream().map(TradeDateDO::getYearWeek).distinct().toList(); Map dateMap = tradeDateDOList.stream().collect(Collectors.toMap(k -> DateUtil.format(k.getTradeDate(), DateConst.YYYY_MM_DD), v -> v)); Map> yearWeekDateMap = tradeDateDOList.stream().collect(Collectors.groupingBy(TradeDateDO::getYearWeek)); // 得到startDate~endDate的最后一个交易日 List dateList = CollUtil.newArrayList(); yearWeekDateMap.forEach((k, v) -> { String date = v.stream().max(Comparator.comparing(TradeDateDO::getTradeDate)).map(e -> DateUtil.format(e.getTradeDate(), DateConst.YYYY_MM_DD)).orElse(null); dateList.add(date); }); for (String date : dateList) { TradeDateDO tradeDateDO = dateMap.get(date); Integer yearWeek = tradeDateDO.getYearWeek(); TradeDateDTO tradeDateDTO = new TradeDateDTO(); tradeDateDTO.setWeek(tradeDateDO.getWeekOfYear()); tradeDateDTO.setYear(tradeDateDO.getEndYear()); String firstDate = yearWeekDateMap.get(yearWeek).stream() .min(Comparator.comparing(TradeDateDO::getTradeDate)).map(e -> DateUtil.format(e.getTradeDate(), DateConst.YYYY_MM_DD)).orElse(null); tradeDateDTO.setFirstDate(firstDate); tradeDateDTO.setLastDate(date); int competitionWeek = (int) yearWeekList.stream().filter(e -> e.compareTo(yearWeek) < 0).count() + 1; tradeDateDTO.setCompetitionWeek(competitionWeek); tradeDateDoMap.put(date, tradeDateDTO); } return tradeDateDoMap; } }