|
@@ -0,0 +1,603 @@
|
|
|
+package com.simuwang.daq.service;
|
|
|
+
|
|
|
+import cn.hutool.core.collection.CollUtil;
|
|
|
+import cn.hutool.core.collection.CollectionUtil;
|
|
|
+import cn.hutool.core.date.DateTime;
|
|
|
+import cn.hutool.core.date.StopWatch;
|
|
|
+import cn.hutool.core.exceptions.ExceptionUtil;
|
|
|
+import cn.hutool.core.util.StrUtil;
|
|
|
+import com.simuwang.base.common.conts.HoldingType;
|
|
|
+import com.simuwang.base.common.util.ValuationBusinessUtils;
|
|
|
+import com.simuwang.base.common.util.ValuationDataUtils;
|
|
|
+import com.simuwang.base.common.util.ValuationTableParseUtil;
|
|
|
+import com.simuwang.base.mapper.*;
|
|
|
+import com.simuwang.base.pojo.dos.*;
|
|
|
+import com.simuwang.base.pojo.valuation.*;
|
|
|
+import com.smppw.utils.BigDecimalUtils;
|
|
|
+import com.smppw.utils.DateUtil;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.beans.factory.annotation.Qualifier;
|
|
|
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.util.*;
|
|
|
+import java.util.concurrent.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+@Service
|
|
|
+public class ValuationParseService {
|
|
|
+
|
|
|
+ private static final Logger log = LoggerFactory.getLogger(ValuationParseService.class);
|
|
|
+
|
|
|
+ public static final int stepSize = 10000;
|
|
|
+
|
|
|
+ private final ValuationMarketCodeMapper valuationMarketCodeMapper;
|
|
|
+ private final FundPositionDetailMapper fundPositionDetailMapper;
|
|
|
+ private final ValuationTableMapper valuationTableMapper;
|
|
|
+ private final FundService fundService;
|
|
|
+ private final PdfValuationRecordMapper pdfValuationRecordMapper;
|
|
|
+ private final ThreadPoolTaskExecutor executor;
|
|
|
+ private final ValuationTableAttributeMapper valuationTableAttributeMapper;
|
|
|
+
|
|
|
+ public ValuationParseService(ValuationMarketCodeMapper valuationMarketCodeMapper, FundPositionDetailMapper fundPositionDetailMapper,
|
|
|
+ ValuationTableMapper valuationTableMapper, FundService fundService,
|
|
|
+ PdfValuationRecordMapper pdfValuationRecordMapper, @Qualifier("valuationExecutor") ThreadPoolTaskExecutor executor,
|
|
|
+ ValuationTableAttributeMapper valuationTableAttributeMapper) {
|
|
|
+ this.valuationMarketCodeMapper = valuationMarketCodeMapper;
|
|
|
+ this.fundPositionDetailMapper = fundPositionDetailMapper;
|
|
|
+ this.valuationTableMapper = valuationTableMapper;
|
|
|
+ this.fundService = fundService;
|
|
|
+ this.pdfValuationRecordMapper = pdfValuationRecordMapper;
|
|
|
+ this.executor = executor;
|
|
|
+ this.valuationTableAttributeMapper = valuationTableAttributeMapper;
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<AssetsValuationResult.Record> parseValuationExcel(List<ValuationNeedParseParam> valuationNeedParseParams) {
|
|
|
+ if (CollUtil.isEmpty(valuationNeedParseParams)) {
|
|
|
+ return CollUtil.newArrayList();
|
|
|
+ }
|
|
|
+ StopWatch stopWatch = new StopWatch();
|
|
|
+ stopWatch.start("create valuation executor");
|
|
|
+ stopWatch.stop();
|
|
|
+ log.info("create valuation executor cost -> {}", stopWatch.prettyPrint(TimeUnit.MILLISECONDS));
|
|
|
+ List<AssetsValuationResult.Record> records = CollectionUtil.newArrayList();
|
|
|
+ List<Future<ValuationResult>> futureList = CollectionUtil.newArrayList();
|
|
|
+ List<String> marketCodeList = valuationMarketCodeMapper.queryMarketCode();
|
|
|
+ try {
|
|
|
+ for (ValuationNeedParseParam valuationNeedParseParam : valuationNeedParseParams) {
|
|
|
+ ParseValuationInfo parseValuationInfo;
|
|
|
+ AssetsValuationResult.Record record = new AssetsValuationResult.Record();
|
|
|
+ PreAssetsValuationInfo<PreAssetsValuationBase> preAssetsValuationInfo = ValuationBusinessUtils.importFile(valuationNeedParseParam);
|
|
|
+ PreAssetsValuationInfo<PreAssetsValuationBase>.Error error = preAssetsValuationInfo.getError();
|
|
|
+ if (error != null) {
|
|
|
+ error = preAssetsValuationInfo.getError();
|
|
|
+ record.setExcelName(error.getExcelName()).setMsg(error.getMsg()).setRowNum(error.getRowNum()).setColumnNum(error.getCellNum())
|
|
|
+ .setSuccess(0);
|
|
|
+ records.add(record);
|
|
|
+ } else {
|
|
|
+ AssetsValuationExcelInfo<AssetsValuationInfo> excelInfo = processDataV2(preAssetsValuationInfo);
|
|
|
+ // 邮件解析 -> 需要根据备案编码和基金名称去查询对应的基金id
|
|
|
+ if (StringUtils.isEmpty(valuationNeedParseParam.getFundId())) {
|
|
|
+ String headInfo = excelInfo.getExtInfo().getHeadInfo();
|
|
|
+ if (StringUtils.isNotEmpty(headInfo)) {
|
|
|
+ AssetsValuationDetails details = excelInfo.getExtInfo();
|
|
|
+
|
|
|
+ parseValuationInfo = parseRegisterNumAndFundName(headInfo);
|
|
|
+ record.setParseValuationInfo(parseValuationInfo);
|
|
|
+ log.info("表格:{},从表格中解析到的基金名称和备案编码:{}", valuationNeedParseParam.getOriginFileName(), parseValuationInfo.toString());
|
|
|
+
|
|
|
+ List<FundInfoDO> fundInfoDOList = fundService.getFundInfoByNamesAndCode(parseValuationInfo.getFundName(), parseValuationInfo.getRegisterNumber());
|
|
|
+ log.info("表格:{}, 匹配上的基金:{}", valuationNeedParseParam.getOriginFileName(), fundInfoDOList);
|
|
|
+ if (CollUtil.isEmpty(fundInfoDOList)) {
|
|
|
+ record.setExcelName(valuationNeedParseParam.getOriginFileName());
|
|
|
+ record.setMsg("未匹配基金");
|
|
|
+ record.setDate(details.getValuationDate());
|
|
|
+ record.setSuccess(0);
|
|
|
+ records.add(record);
|
|
|
+ } else {
|
|
|
+ for (FundInfoDO fundInfoDO : fundInfoDOList) {
|
|
|
+ String fundId = fundInfoDO.getFundId();
|
|
|
+ AssetsValuationResult.Record singleFundRecord = new AssetsValuationResult.Record();
|
|
|
+ singleFundRecord.setExcelName(valuationNeedParseParam.getOriginFileName());
|
|
|
+ singleFundRecord.setDate(details.getValuationDate());
|
|
|
+ singleFundRecord.setSuccess(1);
|
|
|
+ singleFundRecord.setFundId(fundId);
|
|
|
+ singleFundRecord.setCumulativeNavWithdrawal(String.valueOf(details.getCumulativeNav()));
|
|
|
+ singleFundRecord.setNav(String.valueOf(details.getNav()));
|
|
|
+ singleFundRecord.setParseValuationInfo(parseValuationInfo);
|
|
|
+ String valuationDate = details.getValuationDate();
|
|
|
+ List<AssetsValuationInfo> data = excelInfo.getData();
|
|
|
+ if (CollUtil.isNotEmpty(data)) {
|
|
|
+ ValuationTableDO tableInfo = new ValuationTableDO();
|
|
|
+ Integer valuationId = trans2UserValuationDoAndWrite(details, 0, fundId, tableInfo, valuationNeedParseParam);
|
|
|
+ singleFundRecord.setValuationId(valuationId);
|
|
|
+ Future<ValuationResult> future = executor.submit(() -> {
|
|
|
+ ValuationResult valuationResult = new ValuationResult();
|
|
|
+ valuationResult.setFundId(fundId);
|
|
|
+ List<CmValuationTableAttribute> valuationTableAttributes = ValuationTableParseUtil.getAttrList(data);
|
|
|
+ List<FundPositionDetailDO> fundPositionDetailDOList = ValuationTableParseUtil.parseDataNew(valuationTableAttributes, tableInfo, marketCodeList);
|
|
|
+ if (CollectionUtil.isNotEmpty(fundPositionDetailDOList)) {
|
|
|
+ fundPositionDetailDOList.stream().filter(p -> "202".equals(p.getSecuritiesCode())).findFirst()
|
|
|
+ .ifPresent(p -> valuationResult.setCumulativeNavWithdrawal(p.getMarketValue() != null ? String.valueOf(p.getMarketValue()) : null));
|
|
|
+ }
|
|
|
+ valuationResult.setValuationTableAttributes(valuationTableAttributes);
|
|
|
+ valuationResult.setList(fundPositionDetailDOList);
|
|
|
+ valuationResult.setRecord(singleFundRecord);
|
|
|
+ valuationResult.setValuationDate(valuationDate);
|
|
|
+ return valuationResult;
|
|
|
+ });
|
|
|
+ futureList.add(future);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ String fundId = valuationNeedParseParam.getFundId();
|
|
|
+ AssetsValuationDetails details = excelInfo.getExtInfo();
|
|
|
+ record.setNav(String.valueOf(details.getNav()));
|
|
|
+ record.setCumulativeNavWithdrawal(String.valueOf(details.getCumulativeNav()));
|
|
|
+ record.setExcelName(valuationNeedParseParam.getOriginFileName());
|
|
|
+ record.setDate(details.getValuationDate());
|
|
|
+ record.setSuccess(1);
|
|
|
+ record.setFundId(fundId);
|
|
|
+ String valuationDate = details.getValuationDate();
|
|
|
+ List<AssetsValuationInfo> data = excelInfo.getData();
|
|
|
+ if (CollectionUtil.isNotEmpty(data)) {
|
|
|
+ ValuationTableDO tableInfo = new ValuationTableDO();
|
|
|
+ Integer valuationId = trans2UserValuationDoAndWrite(details, 0, fundId, tableInfo, valuationNeedParseParam);
|
|
|
+ record.setValuationId(valuationId);
|
|
|
+ Future<ValuationResult> future = executor.submit(() -> {
|
|
|
+ long startTime = System.currentTimeMillis();
|
|
|
+ ValuationResult valuationResult = new ValuationResult();
|
|
|
+ valuationResult.setFundId(fundId);
|
|
|
+ valuationResult.setUserId(0);
|
|
|
+ List<FundPositionDetailDO> fundPositionDetailDOList = CollUtil.newArrayList();
|
|
|
+ try {
|
|
|
+ List<CmValuationTableAttribute> valuationTableAttributes = ValuationTableParseUtil.getAttrList(data);
|
|
|
+ valuationResult.setValuationTableAttributes(valuationTableAttributes);
|
|
|
+ fundPositionDetailDOList = ValuationTableParseUtil.parseDataNew(valuationTableAttributes, tableInfo, marketCodeList);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.info("Exception: {}", ExceptionUtil.stacktraceToString(e));
|
|
|
+ }
|
|
|
+ if (CollectionUtil.isNotEmpty(fundPositionDetailDOList)) {
|
|
|
+ fundPositionDetailDOList.stream().filter(p -> "202".equals(p.getSecuritiesCode())).findFirst()
|
|
|
+ .ifPresent(p -> valuationResult.setCumulativeNavWithdrawal(p.getMarketValue() != null ? String.valueOf(p.getMarketValue()) : null));
|
|
|
+ }
|
|
|
+ valuationResult.setList(fundPositionDetailDOList);
|
|
|
+ valuationResult.setRecord(record);
|
|
|
+ valuationResult.setValuationDate(valuationDate);
|
|
|
+ long endTime = System.currentTimeMillis();
|
|
|
+ log.info("end parse -> {},spend time -> {}", record.excelName, (endTime - startTime) + "ms");
|
|
|
+ return valuationResult;
|
|
|
+ });
|
|
|
+ futureList.add(future);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (Future<ValuationResult> future : futureList) {
|
|
|
+ try {
|
|
|
+ ValuationResult r = future.get(3600, TimeUnit.SECONDS);
|
|
|
+ String fundId = r.getFundId();
|
|
|
+ AssetsValuationResult.Record record = r.getRecord();
|
|
|
+ record.setCumulativeNavWithdrawal(record.getCumulativeNavWithdrawal());
|
|
|
+ // 获取资产净值和资产份额
|
|
|
+ BigDecimal assetNet = r.getList().stream().filter(e -> StrUtil.isNotBlank(e.getSecuritiesCode()) && "112".equals(e.getSecuritiesCode()))
|
|
|
+ .findFirst().map(FundPositionDetailDO::getMarketValue).orElse(null);
|
|
|
+ BigDecimal assetShare = r.getList().stream().filter(e -> StrUtil.isNotBlank(e.getSecuritiesCode()) && "107".equals(e.getSecuritiesCode()))
|
|
|
+ .findFirst().map(FundPositionDetailDO::getMarketValue).orElse(null);
|
|
|
+ record.setAssetNet(assetNet != null ? String.valueOf(assetNet) : null);
|
|
|
+ record.setAssetShare(assetShare != null ? String.valueOf(assetShare) : null);
|
|
|
+ records.add(record);
|
|
|
+ Integer valuationId = record.getValuationId();
|
|
|
+ List<CmValuationTableAttribute> valuationTableAttributes = r.getValuationTableAttributes();
|
|
|
+ // 保存估值表原始信息
|
|
|
+ saveValuationTableAttribute(valuationId, valuationTableAttributes);
|
|
|
+ // 保存估值表持仓明细信息
|
|
|
+ saveFundPositionDetail(r.getList(), fundId, r.getValuationDate());
|
|
|
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
|
|
|
+ log.info("valuation excel upload future exec exception: {}", e.getMessage(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception exception) {
|
|
|
+ log.error("parse valuation excel error ->{}", ExceptionUtil.stacktraceToString(exception));
|
|
|
+ } finally {
|
|
|
+ stopWatch.start("destruction valuation executor");
|
|
|
+ stopWatch.stop();
|
|
|
+ log.info("destruction valuation executor cost -> {}", stopWatch.prettyPrint(TimeUnit.MILLISECONDS));
|
|
|
+ }
|
|
|
+ //保存PDF估值表记录
|
|
|
+ savePdfValuationRecord(valuationNeedParseParams, records);
|
|
|
+ return records;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void saveValuationTableAttribute(Integer valuationId, List<CmValuationTableAttribute> valuationTableAttributes) {
|
|
|
+ if (valuationId == null || CollUtil.isEmpty(valuationTableAttributes)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ List<ValuationTableAttributeDO> valuationTableAttributeDOList = buildValuationTableAttributeDO(valuationId, valuationTableAttributes);
|
|
|
+ valuationTableAttributeMapper.deleteByValuationId(valuationId);
|
|
|
+ if (CollUtil.isNotEmpty(valuationTableAttributeDOList)) {
|
|
|
+ valuationTableAttributeMapper.batchInsert(valuationTableAttributeDOList);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<ValuationTableAttributeDO> buildValuationTableAttributeDO(Integer valuationId, List<CmValuationTableAttribute> valuationTableAttributes) {
|
|
|
+ if (CollUtil.isEmpty(valuationTableAttributes)) {
|
|
|
+ return CollUtil.newArrayList();
|
|
|
+ }
|
|
|
+ return valuationTableAttributes.stream().map(e -> {
|
|
|
+ ValuationTableAttributeDO tableAttributeDO = new ValuationTableAttributeDO();
|
|
|
+ tableAttributeDO.setValuationId(valuationId);
|
|
|
+ tableAttributeDO.setSubjectCode(e.getOriginalSubjectCode());
|
|
|
+ tableAttributeDO.setSubjectName(e.getSubjectName());
|
|
|
+ tableAttributeDO.setCurrency(e.getCurrency());
|
|
|
+ tableAttributeDO.setExchangeRate(e.getExchangeRate());
|
|
|
+ tableAttributeDO.setSecuritiesAmount(e.getSecuritiesAmount());
|
|
|
+ tableAttributeDO.setUnitCost(e.getUnitCost());
|
|
|
+ tableAttributeDO.setOriCurrencyCost(e.getOCurrencyCost());
|
|
|
+ tableAttributeDO.setNetCost(e.getNetCost());
|
|
|
+ tableAttributeDO.setNetCostRatio(e.getNetCostRatio());
|
|
|
+ tableAttributeDO.setMarketPrice(e.getMarketPrice());
|
|
|
+ tableAttributeDO.setOriCurrencyMarketValue(e.getOCurrencyMarketValue());
|
|
|
+ tableAttributeDO.setMarketValue(e.getMarketValue());
|
|
|
+ tableAttributeDO.setMarketValueRatio(e.getMarketValueRatio());
|
|
|
+ tableAttributeDO.setOriCurrencyIncrement(e.getOCurrencyMarketValue());
|
|
|
+ tableAttributeDO.setIncrement(e.getIncrement());
|
|
|
+ tableAttributeDO.setHaltInfo(e.getHaltInfo());
|
|
|
+ tableAttributeDO.setRightsInterestsInfo(e.getRightsInterestsInfo());
|
|
|
+ tableAttributeDO.setIsvalid(1);
|
|
|
+ tableAttributeDO.setCreatorId(0);
|
|
|
+ tableAttributeDO.setUpdaterId(0);
|
|
|
+ tableAttributeDO.setCreateTime(new Date());
|
|
|
+ tableAttributeDO.setUpdateTime(new Date());
|
|
|
+ return tableAttributeDO;
|
|
|
+ }).collect(Collectors.toList());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 保存PDF估值表记录
|
|
|
+ *
|
|
|
+ * @param valuationNeedParseParams 估值表解析参数
|
|
|
+ * @param records 估值表解析结果
|
|
|
+ */
|
|
|
+ private void savePdfValuationRecord(List<ValuationNeedParseParam> valuationNeedParseParams, List<AssetsValuationResult.Record> records) {
|
|
|
+ if (CollUtil.isEmpty(records)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ List<AssetsValuationResult.Record> pdfRecordList = records.stream().filter(e -> e.getExcelName().endsWith("pdf")).collect(Collectors.toList());
|
|
|
+ if (CollUtil.isEmpty(pdfRecordList)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ List<PdfValuationRecordDO> pdfValuationRecordDoList = buildCmPdfValuationRecordDo(valuationNeedParseParams, pdfRecordList);
|
|
|
+ if (CollUtil.isNotEmpty(pdfValuationRecordDoList)) {
|
|
|
+ pdfValuationRecordMapper.batchInsert(pdfValuationRecordDoList);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<PdfValuationRecordDO> buildCmPdfValuationRecordDo(List<ValuationNeedParseParam> valuationNeedParseParams,
|
|
|
+ List<AssetsValuationResult.Record> pdfRecordList) {
|
|
|
+ if (CollUtil.isEmpty(pdfRecordList)) {
|
|
|
+ return CollUtil.newArrayList();
|
|
|
+ }
|
|
|
+ Map<String, ValuationNeedParseParam> needParseParamMap = valuationNeedParseParams.stream()
|
|
|
+ .collect(Collectors.toMap(ValuationNeedParseParam::getOriginFileName, v -> v));
|
|
|
+ return pdfRecordList.stream().map(e -> {
|
|
|
+ PdfValuationRecordDO pdfValuationRecordDo = new PdfValuationRecordDO();
|
|
|
+ ValuationNeedParseParam parseParam = needParseParamMap.get(e.getExcelName());
|
|
|
+ if (parseParam != null) {
|
|
|
+ pdfValuationRecordDo.setUploadDate(new Date());
|
|
|
+ pdfValuationRecordDo.setExcelUrl(parseParam.getFile().getAbsolutePath());
|
|
|
+ pdfValuationRecordDo.setPdfUrl(parseParam.getFileUrl());
|
|
|
+ pdfValuationRecordDo.setFromEmail(parseParam.getFromEmail() == 1 ? 1 : 0);
|
|
|
+ }
|
|
|
+ pdfValuationRecordDo.setFundId(e.getFundId());
|
|
|
+ pdfValuationRecordDo.setFileName(e.getExcelName());
|
|
|
+ pdfValuationRecordDo.setIsSuccess(e.getSuccess());
|
|
|
+ pdfValuationRecordDo.setReason(e.getMsg());
|
|
|
+ pdfValuationRecordDo.setCreatorId(0);
|
|
|
+ pdfValuationRecordDo.setUpdaterId(0);
|
|
|
+ pdfValuationRecordDo.setCreateTime(new Date());
|
|
|
+ pdfValuationRecordDo.setUpdateTime(new Date());
|
|
|
+ pdfValuationRecordDo.setIsvalid(1);
|
|
|
+ return pdfValuationRecordDo;
|
|
|
+ }).collect(Collectors.toList());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解析备案编码和备案编码
|
|
|
+ *
|
|
|
+ * @param headInfo excel第一行和第二行的内容,中间以'@'符号分隔
|
|
|
+ * @return 备案编码和备案编码
|
|
|
+ */
|
|
|
+ public ParseValuationInfo parseRegisterNumAndFundName(String headInfo) {
|
|
|
+ ParseValuationInfo info = new ParseValuationInfo();
|
|
|
+ if (StringUtils.isNotEmpty(headInfo)) {
|
|
|
+ List<String> contentList = Arrays.stream(headInfo.split("@")).collect(Collectors.toList());
|
|
|
+ for (String content : contentList) {
|
|
|
+ String registerNumber = content.length() > 6 ? content.substring(0, 6) : null;
|
|
|
+ if (StrUtil.isNotBlank(registerNumber) && !ValuationDataUtils.hasChinese(registerNumber, false)) {
|
|
|
+ info.setRegisterNumber(registerNumber);
|
|
|
+ }
|
|
|
+ if (content.contains("估值表") || content.contains("专用表")) {
|
|
|
+ String originRegisterNumber = info.getRegisterNumber();
|
|
|
+ String originFundName = info.getFundName();
|
|
|
+ if (content.contains("___")) {
|
|
|
+ List<String> collect = Arrays.stream(content.split("___")).collect(Collectors.toList());
|
|
|
+ if (collect.size() == 4 && content.contains("专用表")) {
|
|
|
+ info.setRegisterNumber(collect.get(1));
|
|
|
+ info.setFundName(collect.get(2));
|
|
|
+ } else {
|
|
|
+ if (CollUtil.isNotEmpty(collect) && StrUtil.isBlank(originRegisterNumber) && !ValuationDataUtils.hasChinese(registerNumber, false)) {
|
|
|
+ originRegisterNumber = collect.get(0);
|
|
|
+ info.setRegisterNumber(originRegisterNumber);
|
|
|
+ }
|
|
|
+ originFundName = collect.size() == 2 ? collect.get(0) : originFundName;
|
|
|
+ originFundName = collect.size() > 2 ? collect.get(1) : originFundName;
|
|
|
+ info.setFundName(originFundName);
|
|
|
+ }
|
|
|
+
|
|
|
+ } else if (content.contains("__")) {
|
|
|
+ List<String> collect = Arrays.stream(content.split("__")).collect(Collectors.toList());
|
|
|
+ if (collect.size() == 4 && content.contains("专用表")) {
|
|
|
+ info.setRegisterNumber(collect.get(1));
|
|
|
+ info.setFundName(collect.get(2));
|
|
|
+ } else {
|
|
|
+ if (CollUtil.isNotEmpty(collect) && StrUtil.isBlank(originRegisterNumber) && !ValuationDataUtils.hasChinese(registerNumber, false)) {
|
|
|
+ originRegisterNumber = collect.get(0);
|
|
|
+ info.setRegisterNumber(originRegisterNumber);
|
|
|
+ }
|
|
|
+ originFundName = collect.size() == 2 ? collect.get(0) : originFundName;
|
|
|
+ originFundName = collect.size() > 2 ? collect.get(1) : originFundName;
|
|
|
+ info.setFundName(originFundName);
|
|
|
+ }
|
|
|
+ } else if (content.contains("_")) {
|
|
|
+ List<String> collect = Arrays.stream(content.split("_")).collect(Collectors.toList());
|
|
|
+ if (collect.size() == 4 && content.contains("专用表")) {
|
|
|
+ info.setRegisterNumber(collect.get(1));
|
|
|
+ info.setFundName(collect.get(2));
|
|
|
+ } else {
|
|
|
+ if (CollUtil.isNotEmpty(collect) && StrUtil.isBlank(originRegisterNumber) && !ValuationDataUtils.hasChinese(registerNumber, false)) {
|
|
|
+ originRegisterNumber = collect.get(0);
|
|
|
+ info.setRegisterNumber(originRegisterNumber);
|
|
|
+ }
|
|
|
+ originFundName = collect.size() == 2 ? collect.get(0) : originFundName;
|
|
|
+ originFundName = collect.size() > 2 ? collect.get(1) : originFundName;
|
|
|
+ info.setFundName(originFundName);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //兼容格式: xxx估值表@基金名称 -> 只能识别到基金名称
|
|
|
+ if (StrUtil.isBlank(info.getFundName()) && StrUtil.isBlank(info.getRegisterNumber())) {
|
|
|
+ List<String> contentList = Arrays.stream(headInfo.split("@")).collect(Collectors.toList());
|
|
|
+ if (CollUtil.isNotEmpty(contentList) && contentList.size() >= 2) {
|
|
|
+ String fundName = !contentList.get(1).contains("_") ? contentList.get(1) : null;
|
|
|
+ info.setFundName(fundName);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 兼容格式:编码编码+基金名称+日期+估值报表四级 -> SXT974同增FOF稳增1期私募证券投资基金2024年08月02日估值报表四级
|
|
|
+ if (StrUtil.isBlank(info.getFundName()) && StrUtil.isNotBlank(info.getRegisterNumber())) {
|
|
|
+ int index = StrUtil.indexOfIgnoreCase(headInfo, "私募证券投资基金");
|
|
|
+ // 说明找到了
|
|
|
+ if (index != -1) {
|
|
|
+ String shortName = headInfo.substring(0, StrUtil.indexOfIgnoreCase(headInfo, "私募证券投资基金"));
|
|
|
+ String fundName = shortName.replace(info.getRegisterNumber(), "") + "私募证券投资基金";
|
|
|
+ info.setFundName(fundName);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return info;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void saveFundPositionDetail(List<FundPositionDetailDO> fundPositionDetails, String fundId, String valuationDate) {
|
|
|
+ int subBegin = 0;
|
|
|
+ int subEnd = stepSize;
|
|
|
+ int insertNum = 0;
|
|
|
+ int hasStock = 0;
|
|
|
+ int hasBond = 0;
|
|
|
+ int hasFuture = 0;
|
|
|
+ if (CollectionUtil.isNotEmpty(fundPositionDetails)) {
|
|
|
+ //插入持仓数据 cm_fund_position_detail(记录数较多,得分批)
|
|
|
+ // 先删除原先的数据 然后写入数据
|
|
|
+ fundPositionDetailMapper.deleteUnUsed(fundId, valuationDate);
|
|
|
+ // 将最终结果写入 cm_fund_position_detail
|
|
|
+ while (subBegin < fundPositionDetails.size()) {
|
|
|
+ List<FundPositionDetailDO> segment = fundPositionDetails.subList(subBegin, Math.min(subEnd, fundPositionDetails.size()));
|
|
|
+ for (FundPositionDetailDO fundPositionDetail : segment) {
|
|
|
+ //实收信托、实收资本对应的编码为107
|
|
|
+ if (StrUtil.isNotBlank(fundPositionDetail.getSecuritiesName()) && "实收信托".equals(fundPositionDetail.getSecuritiesName().trim())) {
|
|
|
+ fundPositionDetail.setSubjectCode("107");
|
|
|
+ fundPositionDetail.setSecuritiesCode("107");
|
|
|
+ }
|
|
|
+ //设置创建者id,在拿取最近修改人时有用
|
|
|
+ fundPositionDetail.setCreatorId(0);
|
|
|
+ if (fundPositionDetail.getLevel() != null && fundPositionDetail.getLevel() >= 4) {
|
|
|
+ Integer secType = fundPositionDetail.getSecType();
|
|
|
+ Integer subType = fundPositionDetail.getSubType();
|
|
|
+ if (secType != null && subType != null) {
|
|
|
+ if (secType == HoldingType.Stock.getId() && subType == HoldingType.Stock.getId()) {
|
|
|
+ hasStock = 1;
|
|
|
+ }
|
|
|
+ // 正逆回购不属于债券
|
|
|
+ String subjectCode = fundPositionDetail.getSubjectCode();
|
|
|
+ String[] SALE_CODES = {"2202", "1202"};
|
|
|
+ if (secType == HoldingType.Bond.getId() && !StrUtil.containsAny(subjectCode, SALE_CODES)) {
|
|
|
+ hasBond = 1;
|
|
|
+ }
|
|
|
+ if (secType == HoldingType.Future.getId() || secType == HoldingType.Option.getId()) {
|
|
|
+ hasFuture = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ insertNum += fundPositionDetailMapper.insertMulti(segment);
|
|
|
+ subBegin = subEnd;
|
|
|
+ subEnd += stepSize;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 更新 cm_user_valuation_table
|
|
|
+ if (insertNum > 0) {
|
|
|
+ valuationTableMapper.updateUpdateAnalyzed(fundId, valuationDate, hasStock, hasBond, hasFuture);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public Integer trans2UserValuationDoAndWrite(AssetsValuationDetails details, Integer userId, String fundId,
|
|
|
+ ValuationTableDO tableInfo, ValuationNeedParseParam valuationNeedParseParam) {
|
|
|
+ valuationTableMapper.unValid(fundId, details.getValuationDate());
|
|
|
+ tableInfo.setFundId(fundId);
|
|
|
+ tableInfo.setValuationDate(DateUtil.StringToDate(details.getValuationDate()));
|
|
|
+ tableInfo.setIsAnalyzed(0);
|
|
|
+ tableInfo.setIsvalid(1);
|
|
|
+ tableInfo.setCreateTime(DateTime.now());
|
|
|
+ tableInfo.setUpdateTime(DateTime.now());
|
|
|
+ tableInfo.setCreatorId(userId);
|
|
|
+ tableInfo.setUpdaterId(userId);
|
|
|
+ tableInfo.setTotalMarketValue(BigDecimalUtils.toBigDecimal(details.getTotalMarketValue()));
|
|
|
+ tableInfo.setNetAssetsValue(BigDecimalUtils.toBigDecimal(details.getNetAssetsValue()));
|
|
|
+ tableInfo.setIncrement(BigDecimalUtils.toBigDecimal(details.getIncrement()));
|
|
|
+ tableInfo.setTitle(details.getTitle());
|
|
|
+ tableInfo.setNav(BigDecimalUtils.toBigDecimal(details.getNav()));
|
|
|
+ tableInfo.setFileUrl(valuationNeedParseParam.getFileUrl());
|
|
|
+ tableInfo.setHeadInfo(details.getHeadInfo());
|
|
|
+ tableInfo.setTailInfo(details.getTailInfo());
|
|
|
+ tableInfo.setTableType(details.getType());
|
|
|
+ tableInfo.setFromEmail(valuationNeedParseParam.getFromEmail());
|
|
|
+ tableInfo.setOriginalFile(valuationNeedParseParam.getOriginFileName());
|
|
|
+ tableInfo.setConvertedFile(valuationNeedParseParam.getFile().getName());
|
|
|
+ valuationTableMapper.insert(tableInfo);
|
|
|
+ return tableInfo.getId();
|
|
|
+ }
|
|
|
+
|
|
|
+ public AssetsValuationExcelInfo<AssetsValuationInfo> processDataV2(PreAssetsValuationInfo<PreAssetsValuationBase> info) {
|
|
|
+ AssetsValuationExcelInfo<AssetsValuationInfo> avInfo = new AssetsValuationExcelInfo<>();
|
|
|
+
|
|
|
+ AssetsValuationDetails extInfo = new AssetsValuationDetails();
|
|
|
+ extInfo.setTailInfo(list2String(info.getFooter()));
|
|
|
+ extInfo.setHeadInfo(list2String(info.getHeader().getHeaderList()));
|
|
|
+ extInfo.setOriginalfile(info.getExcelOriginName());
|
|
|
+ extInfo.setConvertedFile(info.getExcelNewName());
|
|
|
+ extInfo.setFileUrl(info.getSavePath());
|
|
|
+ extInfo.setTitle(info.getHeader().getTitle());
|
|
|
+ extInfo.setType(info.getType().getId());
|
|
|
+ extInfo.setNav(info.getHeader().getUnitNetValue());
|
|
|
+ extInfo.setUserId(ValuationDataUtils.string2Int(info.getUserId()));
|
|
|
+ extInfo.setValuationDate(new Date(info.getHeader().getValuationDate().getTime()));
|
|
|
+
|
|
|
+ List<PreAssetsValuationBase> lBases = info.getData();
|
|
|
+ ValuationDataUtils.removeUnderLine(lBases);
|
|
|
+ List<AssetsValuationInfo> list = new ArrayList<>(lBases.size());
|
|
|
+
|
|
|
+ //现在业务需要保存基金的总资产 总资产 资产净值 直接从解析结果获取
|
|
|
+ Double totalMarketValue = null;
|
|
|
+ // 总资产净值
|
|
|
+ Double netAssetMarketValue = null;
|
|
|
+ // 基金估值增值
|
|
|
+ Double increment = null;
|
|
|
+
|
|
|
+ for (int i = 0; i < lBases.size(); i++) {
|
|
|
+
|
|
|
+ PreAssetsValuationBase d = lBases.get(i);
|
|
|
+
|
|
|
+ if (d.getSubjectCode() == null || d.getSubjectCode().isEmpty()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ String originalSubjectCode = d.getOriginalSubjectCode();
|
|
|
+ if (ValuationDataUtils.checkMarketValue(originalSubjectCode)) {
|
|
|
+ totalMarketValue = ValuationDataUtils.string2Double(d.getMarketValue());
|
|
|
+ }
|
|
|
+ if (ValuationDataUtils.checkNetAssetsValue(originalSubjectCode)) {
|
|
|
+ netAssetMarketValue = ValuationDataUtils.string2Double(d.getMarketValue());
|
|
|
+ increment = ValuationDataUtils.string2Double(d.getValueAdded());
|
|
|
+ }
|
|
|
+
|
|
|
+ AssetsValuationInfo data = new AssetsValuationInfo();
|
|
|
+ data.setUserId(ValuationDataUtils.string2Int(info.getUserId()));
|
|
|
+ data.setSecuritiesAmount(ValuationDataUtils.string2Double(d.getAmount()));
|
|
|
+ data.setHaltInfo(d.getSuspensionInfo());
|
|
|
+ data.setIncrement(ValuationDataUtils.string2Double(d.getValueAdded()));
|
|
|
+ data.setMarketValue(ValuationDataUtils.string2Double(d.getMarketValue()));
|
|
|
+ data.setMarketValueRatio(ValuationDataUtils.string2Double(d.getRatioOfMarketValueToNetWorth()));
|
|
|
+ data.setNetCost(ValuationDataUtils.string2Double(d.getCost()));
|
|
|
+ data.setNetCostRatio(ValuationDataUtils.string2Double(d.getRatioOfCostToNetWorth()));
|
|
|
+ data.setSubjectCode(d.getSubjectCode());
|
|
|
+ data.setSecuritiesCode((d.getSecurtiesCode()));
|
|
|
+ // 对于期权,如果以DR、XR开头,则剔除这两个字母
|
|
|
+ if (data.getSubjectName() != null && (data.getSubjectName().startsWith("DR") || data.getSubjectName().startsWith("XR"))) {
|
|
|
+ String subjectName = data.getSubjectName().replace("DR", "");
|
|
|
+ data.setSubjectName(subjectName.replace("XR", ""));
|
|
|
+ } else {
|
|
|
+ data.setSubjectName(d.getSubjectName());
|
|
|
+ }
|
|
|
+ data.setUnitCost(ValuationDataUtils.string2Double(d.getUnitCost()));
|
|
|
+
|
|
|
+ //寻找累计单位净值
|
|
|
+ if (null == extInfo.getCumulativeNav()) {
|
|
|
+ if (StringUtils.isNotEmpty(d.getSubjectCode()) && d.getSubjectCode().contains("累计单位净值")) {
|
|
|
+ if (StringUtils.isNotEmpty(d.getSubjectName()) && ValuationDataUtils.isNumber(d.getSubjectName())) {
|
|
|
+ extInfo.setCumulativeNav(Double.valueOf(d.getSubjectName()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (d.getType()) {
|
|
|
+ case GeneralTemplate:
|
|
|
+ PreAssetsValuationGeneralTemplate general = (PreAssetsValuationGeneralTemplate) d;
|
|
|
+ data.setOriginalSubjectCode(general.getOriginalSubjectCode());
|
|
|
+ data.setMarketPrice(ValuationDataUtils.string2Double(general.getMarketPrice()));
|
|
|
+ data.setCurrency(general.getCurrency());
|
|
|
+ data.setExchangeRate(general.getExchangeRate());
|
|
|
+ data.setOriCurrencyCost(ValuationDataUtils.string2Double(general.getOriCurrencyCost()));
|
|
|
+ data.setOriCurrencyMarketValue(ValuationDataUtils.string2Double(general.getOriCurrencyMarketValue()));
|
|
|
+ data.setOriCurrencyValueAdded(ValuationDataUtils.string2Double(general.getOriCurrencyValueAdded()));
|
|
|
+ data.setSubjectLevel(general.getSubjectLevel());
|
|
|
+ data.setIssuer(general.getIssuer());
|
|
|
+ data.setVProjectCode(general.getvProjectCode());
|
|
|
+ data.setVProjectName(general.getvProjectName());
|
|
|
+ data.setCostRatioAsset(general.getCostRatioAsset());
|
|
|
+ data.setMvRatioAsset(general.getMvRatioAsset());
|
|
|
+ data.setSpotPrice(general.getSpotPrice());
|
|
|
+ data.setRemark(general.getRemark());
|
|
|
+ data.setRightsInterestsInfo(general.getRightAndInterestInfo());
|
|
|
+ data.setAssumingCost(general.getAssumingCost());
|
|
|
+ data.setHoldingState(general.getHoldingState());
|
|
|
+
|
|
|
+ if (data.getSubjectName() != null && ValuationDataUtils.isValid(data.getSubjectCode())) {
|
|
|
+ data.setSubjectCode(data.getSubjectCode().replace(".", ""));
|
|
|
+ if (ValuationDataUtils.hasChinese(data.getSubjectCode(), false)) {
|
|
|
+ String code = data.getSubjectCode().replace(data.getSubjectName(), "");
|
|
|
+ code = ValuationDataUtils.getSubjectCode(code);
|
|
|
+ if (code.length() >= 4) {
|
|
|
+ data.setSubjectCode(code);
|
|
|
+ } else {
|
|
|
+ data.setSecType(100);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ list.add(data);
|
|
|
+ }
|
|
|
+ extInfo.setTotalMarketValue(totalMarketValue);
|
|
|
+ extInfo.setNetAssetsValue(netAssetMarketValue);
|
|
|
+ extInfo.setIncrement(increment);
|
|
|
+ avInfo.setExtInfo(extInfo);
|
|
|
+ avInfo.setData(list);
|
|
|
+ return avInfo;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String list2String(List<String> list) {
|
|
|
+ if (CollUtil.isEmpty(list)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return String.join("@", list);
|
|
|
+ }
|
|
|
+}
|