ValuationParseService.java 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. package com.simuwang.daq.service;
  2. import cn.hutool.core.collection.CollUtil;
  3. import cn.hutool.core.collection.CollectionUtil;
  4. import cn.hutool.core.date.DateTime;
  5. import cn.hutool.core.date.StopWatch;
  6. import cn.hutool.core.exceptions.ExceptionUtil;
  7. import cn.hutool.core.util.StrUtil;
  8. import com.simuwang.base.common.conts.HoldingType;
  9. import com.simuwang.base.common.util.ValuationBusinessUtils;
  10. import com.simuwang.base.common.util.ValuationDataUtils;
  11. import com.simuwang.base.common.util.ValuationTableParseUtil;
  12. import com.simuwang.base.mapper.*;
  13. import com.simuwang.base.pojo.dos.*;
  14. import com.simuwang.base.pojo.valuation.*;
  15. import com.smppw.utils.BigDecimalUtils;
  16. import com.smppw.utils.DateUtil;
  17. import org.apache.commons.lang3.StringUtils;
  18. import org.slf4j.Logger;
  19. import org.slf4j.LoggerFactory;
  20. import org.springframework.beans.factory.annotation.Qualifier;
  21. import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
  22. import org.springframework.stereotype.Service;
  23. import java.math.BigDecimal;
  24. import java.util.*;
  25. import java.util.concurrent.*;
  26. import java.util.stream.Collectors;
  27. @Service
  28. public class ValuationParseService {
  29. private static final Logger log = LoggerFactory.getLogger(ValuationParseService.class);
  30. public static final int stepSize = 10000;
  31. private final ValuationMarketCodeMapper valuationMarketCodeMapper;
  32. private final FundPositionDetailMapper fundPositionDetailMapper;
  33. private final ValuationTableMapper valuationTableMapper;
  34. private final FundService fundService;
  35. private final PdfValuationRecordMapper pdfValuationRecordMapper;
  36. private final ThreadPoolTaskExecutor executor;
  37. private final ValuationTableAttributeMapper valuationTableAttributeMapper;
  38. public ValuationParseService(ValuationMarketCodeMapper valuationMarketCodeMapper, FundPositionDetailMapper fundPositionDetailMapper,
  39. ValuationTableMapper valuationTableMapper, FundService fundService,
  40. PdfValuationRecordMapper pdfValuationRecordMapper, @Qualifier("valuationExecutor") ThreadPoolTaskExecutor executor,
  41. ValuationTableAttributeMapper valuationTableAttributeMapper) {
  42. this.valuationMarketCodeMapper = valuationMarketCodeMapper;
  43. this.fundPositionDetailMapper = fundPositionDetailMapper;
  44. this.valuationTableMapper = valuationTableMapper;
  45. this.fundService = fundService;
  46. this.pdfValuationRecordMapper = pdfValuationRecordMapper;
  47. this.executor = executor;
  48. this.valuationTableAttributeMapper = valuationTableAttributeMapper;
  49. }
  50. public List<AssetsValuationResult.Record> parseValuationExcel(List<ValuationNeedParseParam> valuationNeedParseParams) {
  51. if (CollUtil.isEmpty(valuationNeedParseParams)) {
  52. return CollUtil.newArrayList();
  53. }
  54. StopWatch stopWatch = new StopWatch();
  55. stopWatch.start("create valuation executor");
  56. stopWatch.stop();
  57. log.info("create valuation executor cost -> {}", stopWatch.prettyPrint(TimeUnit.MILLISECONDS));
  58. List<AssetsValuationResult.Record> records = CollectionUtil.newArrayList();
  59. List<Future<ValuationResult>> futureList = CollectionUtil.newArrayList();
  60. List<String> marketCodeList = valuationMarketCodeMapper.queryMarketCode();
  61. try {
  62. for (ValuationNeedParseParam valuationNeedParseParam : valuationNeedParseParams) {
  63. ParseValuationInfo parseValuationInfo;
  64. AssetsValuationResult.Record record = new AssetsValuationResult.Record();
  65. PreAssetsValuationInfo<PreAssetsValuationBase> preAssetsValuationInfo = ValuationBusinessUtils.importFile(valuationNeedParseParam);
  66. PreAssetsValuationInfo<PreAssetsValuationBase>.Error error = preAssetsValuationInfo.getError();
  67. if (error != null) {
  68. error = preAssetsValuationInfo.getError();
  69. record.setExcelName(error.getExcelName()).setMsg(error.getMsg()).setRowNum(error.getRowNum()).setColumnNum(error.getCellNum())
  70. .setSuccess(0);
  71. records.add(record);
  72. } else {
  73. AssetsValuationExcelInfo<AssetsValuationInfo> excelInfo = processDataV2(preAssetsValuationInfo);
  74. // 邮件解析 -> 需要根据备案编码和基金名称去查询对应的基金id
  75. if (StringUtils.isEmpty(valuationNeedParseParam.getFundId())) {
  76. String headInfo = excelInfo.getExtInfo().getHeadInfo();
  77. if (StringUtils.isNotEmpty(headInfo)) {
  78. AssetsValuationDetails details = excelInfo.getExtInfo();
  79. parseValuationInfo = parseRegisterNumAndFundName(headInfo);
  80. record.setParseValuationInfo(parseValuationInfo);
  81. log.info("表格:{},从表格中解析到的基金名称和备案编码:{}", valuationNeedParseParam.getOriginFileName(), parseValuationInfo.toString());
  82. List<FundInfoDO> fundInfoDOList = fundService.getFundInfoByNamesAndCode(parseValuationInfo.getFundName(), parseValuationInfo.getRegisterNumber());
  83. log.info("表格:{}, 匹配上的基金:{}", valuationNeedParseParam.getOriginFileName(), fundInfoDOList);
  84. if (CollUtil.isEmpty(fundInfoDOList)) {
  85. // 未匹配基金的情况 -> 不保存估值表信息
  86. record.setNav(String.valueOf(details.getNav()));
  87. record.setCumulativeNavWithdrawal(String.valueOf(details.getCumulativeNav()));
  88. record.setExcelName(valuationNeedParseParam.getOriginFileName());
  89. record.setDate(details.getValuationDate());
  90. record.setExcelName(valuationNeedParseParam.getOriginFileName());
  91. record.setMsg("未匹配基金");
  92. record.setDate(details.getValuationDate());
  93. record.setSuccess(0);
  94. BigDecimal assetNet = details.getNetAssetsValue() != null ? BigDecimal.valueOf(details.getNetAssetsValue()) : null;
  95. BigDecimal assetShare = details.getAssetShare() != null ? BigDecimal.valueOf(details.getAssetShare()) : null;
  96. record.setAssetNet(assetNet != null ? String.valueOf(assetNet) : null);
  97. record.setAssetShare(assetShare != null ? String.valueOf(assetShare) : null);
  98. records.add(record);
  99. } else {
  100. for (FundInfoDO fundInfoDO : fundInfoDOList) {
  101. String fundId = fundInfoDO.getFundId();
  102. AssetsValuationResult.Record singleFundRecord = new AssetsValuationResult.Record();
  103. singleFundRecord.setExcelName(valuationNeedParseParam.getOriginFileName());
  104. singleFundRecord.setDate(details.getValuationDate());
  105. singleFundRecord.setSuccess(1);
  106. singleFundRecord.setFundId(fundId);
  107. singleFundRecord.setCumulativeNavWithdrawal(String.valueOf(details.getCumulativeNav()));
  108. singleFundRecord.setNav(String.valueOf(details.getNav()));
  109. singleFundRecord.setParseValuationInfo(parseValuationInfo);
  110. String valuationDate = details.getValuationDate();
  111. List<AssetsValuationInfo> data = excelInfo.getData();
  112. if (CollUtil.isNotEmpty(data)) {
  113. ValuationTableDO tableInfo = new ValuationTableDO();
  114. Integer valuationId = trans2UserValuationDoAndWrite(details, fundId, tableInfo, valuationNeedParseParam);
  115. singleFundRecord.setValuationId(valuationId);
  116. Future<ValuationResult> future = executor.submit(() -> {
  117. ValuationResult valuationResult = new ValuationResult();
  118. valuationResult.setFundId(fundId);
  119. List<CmValuationTableAttribute> valuationTableAttributes = ValuationTableParseUtil.getAttrList(data);
  120. List<FundPositionDetailDO> fundPositionDetailDOList = ValuationTableParseUtil.parseDataNew(valuationTableAttributes, tableInfo, marketCodeList);
  121. if (CollectionUtil.isNotEmpty(fundPositionDetailDOList)) {
  122. fundPositionDetailDOList.stream().filter(p -> "202".equals(p.getSecuritiesCode())).findFirst()
  123. .ifPresent(p -> valuationResult.setCumulativeNavWithdrawal(p.getMarketValue() != null ? String.valueOf(p.getMarketValue()) : null));
  124. }
  125. valuationResult.setValuationTableAttributes(valuationTableAttributes);
  126. valuationResult.setList(fundPositionDetailDOList);
  127. valuationResult.setRecord(singleFundRecord);
  128. valuationResult.setValuationDate(valuationDate);
  129. return valuationResult;
  130. });
  131. futureList.add(future);
  132. }
  133. }
  134. }
  135. }
  136. } else {
  137. String fundId = valuationNeedParseParam.getFundId();
  138. AssetsValuationDetails details = excelInfo.getExtInfo();
  139. record.setNav(String.valueOf(details.getNav()));
  140. record.setCumulativeNavWithdrawal(String.valueOf(details.getCumulativeNav()));
  141. record.setExcelName(valuationNeedParseParam.getOriginFileName());
  142. record.setDate(details.getValuationDate());
  143. record.setSuccess(1);
  144. record.setFundId(fundId);
  145. String valuationDate = details.getValuationDate();
  146. List<AssetsValuationInfo> data = excelInfo.getData();
  147. if (CollectionUtil.isNotEmpty(data)) {
  148. ValuationTableDO tableInfo = new ValuationTableDO();
  149. Integer valuationId = trans2UserValuationDoAndWrite(details, fundId, tableInfo, valuationNeedParseParam);
  150. record.setValuationId(valuationId);
  151. Future<ValuationResult> future = executor.submit(() -> {
  152. long startTime = System.currentTimeMillis();
  153. ValuationResult valuationResult = new ValuationResult();
  154. valuationResult.setFundId(fundId);
  155. valuationResult.setUserId(0);
  156. List<FundPositionDetailDO> fundPositionDetailDOList = CollUtil.newArrayList();
  157. try {
  158. List<CmValuationTableAttribute> valuationTableAttributes = ValuationTableParseUtil.getAttrList(data);
  159. valuationResult.setValuationTableAttributes(valuationTableAttributes);
  160. fundPositionDetailDOList = ValuationTableParseUtil.parseDataNew(valuationTableAttributes, tableInfo, marketCodeList);
  161. } catch (Exception e) {
  162. log.info("Exception: {}", ExceptionUtil.stacktraceToString(e));
  163. }
  164. if (CollectionUtil.isNotEmpty(fundPositionDetailDOList)) {
  165. fundPositionDetailDOList.stream().filter(p -> "202".equals(p.getSecuritiesCode())).findFirst()
  166. .ifPresent(p -> valuationResult.setCumulativeNavWithdrawal(p.getMarketValue() != null ? String.valueOf(p.getMarketValue()) : null));
  167. }
  168. valuationResult.setList(fundPositionDetailDOList);
  169. valuationResult.setRecord(record);
  170. valuationResult.setValuationDate(valuationDate);
  171. long endTime = System.currentTimeMillis();
  172. log.info("end parse -> {},spend time -> {}", record.excelName, (endTime - startTime) + "ms");
  173. return valuationResult;
  174. });
  175. futureList.add(future);
  176. }
  177. }
  178. }
  179. }
  180. for (Future<ValuationResult> future : futureList) {
  181. try {
  182. ValuationResult r = future.get(3600, TimeUnit.SECONDS);
  183. String fundId = r.getFundId();
  184. AssetsValuationResult.Record record = r.getRecord();
  185. record.setCumulativeNavWithdrawal(record.getCumulativeNavWithdrawal());
  186. // 获取资产净值和资产份额
  187. BigDecimal assetNet = r.getList().stream().filter(e -> StrUtil.isNotBlank(e.getSecuritiesCode()) && "112".equals(e.getSecuritiesCode()))
  188. .findFirst().map(FundPositionDetailDO::getMarketValue).orElse(null);
  189. BigDecimal assetShare = r.getList().stream().filter(e -> StrUtil.isNotBlank(e.getSecuritiesCode()) && "107".equals(e.getSecuritiesCode()))
  190. .findFirst().map(FundPositionDetailDO::getMarketValue).orElse(null);
  191. record.setAssetNet(assetNet != null ? String.valueOf(assetNet) : null);
  192. record.setAssetShare(assetShare != null ? String.valueOf(assetShare) : null);
  193. records.add(record);
  194. Integer valuationId = record.getValuationId();
  195. List<CmValuationTableAttribute> valuationTableAttributes = r.getValuationTableAttributes();
  196. // 保存估值表原始信息
  197. saveValuationTableAttribute(valuationId, valuationTableAttributes);
  198. // 保存估值表持仓明细信息
  199. saveFundPositionDetail(r.getList(), fundId, r.getValuationDate());
  200. } catch (InterruptedException | ExecutionException | TimeoutException e) {
  201. log.info("valuation excel upload future exec exception: {}", e.getMessage(), e);
  202. }
  203. }
  204. } catch (Exception exception) {
  205. log.error("parse valuation excel error ->{}", ExceptionUtil.stacktraceToString(exception));
  206. } finally {
  207. stopWatch.start("destruction valuation executor");
  208. stopWatch.stop();
  209. log.info("destruction valuation executor cost -> {}", stopWatch.prettyPrint(TimeUnit.MILLISECONDS));
  210. }
  211. //保存PDF估值表记录
  212. savePdfValuationRecord(valuationNeedParseParams, records);
  213. return records;
  214. }
  215. private void saveValuationTableAttribute(Integer valuationId, List<CmValuationTableAttribute> valuationTableAttributes) {
  216. if (valuationId == null || CollUtil.isEmpty(valuationTableAttributes)) {
  217. return;
  218. }
  219. List<ValuationTableAttributeDO> valuationTableAttributeDOList = buildValuationTableAttributeDO(valuationId, valuationTableAttributes);
  220. valuationTableAttributeMapper.deleteByValuationId(valuationId);
  221. if (CollUtil.isNotEmpty(valuationTableAttributeDOList)) {
  222. valuationTableAttributeMapper.batchInsert(valuationTableAttributeDOList);
  223. }
  224. }
  225. private List<ValuationTableAttributeDO> buildValuationTableAttributeDO(Integer valuationId, List<CmValuationTableAttribute> valuationTableAttributes) {
  226. if (CollUtil.isEmpty(valuationTableAttributes)) {
  227. return CollUtil.newArrayList();
  228. }
  229. return valuationTableAttributes.stream().map(e -> {
  230. ValuationTableAttributeDO tableAttributeDO = new ValuationTableAttributeDO();
  231. tableAttributeDO.setValuationId(valuationId);
  232. tableAttributeDO.setSubjectCode(e.getOriginalSubjectCode());
  233. tableAttributeDO.setSubjectName(e.getSubjectName());
  234. tableAttributeDO.setCurrency(e.getCurrency());
  235. tableAttributeDO.setExchangeRate(e.getExchangeRate());
  236. tableAttributeDO.setSecuritiesAmount(e.getSecuritiesAmount());
  237. tableAttributeDO.setUnitCost(e.getUnitCost());
  238. tableAttributeDO.setOriCurrencyCost(e.getOCurrencyCost());
  239. tableAttributeDO.setNetCost(e.getNetCost());
  240. tableAttributeDO.setNetCostRatio(e.getNetCostRatio());
  241. tableAttributeDO.setMarketPrice(e.getMarketPrice());
  242. tableAttributeDO.setOriCurrencyMarketValue(e.getOCurrencyMarketValue());
  243. tableAttributeDO.setMarketValue(e.getMarketValue());
  244. tableAttributeDO.setMarketValueRatio(e.getMarketValueRatio());
  245. tableAttributeDO.setOriCurrencyIncrement(e.getOCurrencyMarketValue());
  246. tableAttributeDO.setIncrement(e.getIncrement());
  247. tableAttributeDO.setHaltInfo(e.getHaltInfo());
  248. tableAttributeDO.setRightsInterestsInfo(e.getRightsInterestsInfo());
  249. tableAttributeDO.setIsvalid(1);
  250. tableAttributeDO.setCreatorId(0);
  251. tableAttributeDO.setUpdaterId(0);
  252. tableAttributeDO.setCreateTime(new Date());
  253. tableAttributeDO.setUpdateTime(new Date());
  254. return tableAttributeDO;
  255. }).collect(Collectors.toList());
  256. }
  257. /**
  258. * 保存PDF估值表记录
  259. *
  260. * @param valuationNeedParseParams 估值表解析参数
  261. * @param records 估值表解析结果
  262. */
  263. private void savePdfValuationRecord(List<ValuationNeedParseParam> valuationNeedParseParams, List<AssetsValuationResult.Record> records) {
  264. if (CollUtil.isEmpty(records)) {
  265. return;
  266. }
  267. List<AssetsValuationResult.Record> pdfRecordList = records.stream().filter(e -> e.getExcelName().endsWith("pdf")).collect(Collectors.toList());
  268. if (CollUtil.isEmpty(pdfRecordList)) {
  269. return;
  270. }
  271. List<PdfValuationRecordDO> pdfValuationRecordDoList = buildCmPdfValuationRecordDo(valuationNeedParseParams, pdfRecordList);
  272. if (CollUtil.isNotEmpty(pdfValuationRecordDoList)) {
  273. pdfValuationRecordMapper.batchInsert(pdfValuationRecordDoList);
  274. }
  275. }
  276. private List<PdfValuationRecordDO> buildCmPdfValuationRecordDo(List<ValuationNeedParseParam> valuationNeedParseParams,
  277. List<AssetsValuationResult.Record> pdfRecordList) {
  278. if (CollUtil.isEmpty(pdfRecordList)) {
  279. return CollUtil.newArrayList();
  280. }
  281. Map<String, ValuationNeedParseParam> needParseParamMap = valuationNeedParseParams.stream()
  282. .collect(Collectors.toMap(ValuationNeedParseParam::getOriginFileName, v -> v));
  283. return pdfRecordList.stream().map(e -> {
  284. PdfValuationRecordDO pdfValuationRecordDo = new PdfValuationRecordDO();
  285. ValuationNeedParseParam parseParam = needParseParamMap.get(e.getExcelName());
  286. if (parseParam != null) {
  287. pdfValuationRecordDo.setUploadDate(new Date());
  288. pdfValuationRecordDo.setExcelUrl(parseParam.getFile().getAbsolutePath());
  289. pdfValuationRecordDo.setPdfUrl(parseParam.getFileUrl());
  290. pdfValuationRecordDo.setFromEmail(parseParam.getFromEmail() == 1 ? 1 : 0);
  291. }
  292. pdfValuationRecordDo.setFundId(e.getFundId());
  293. pdfValuationRecordDo.setFileName(e.getExcelName());
  294. pdfValuationRecordDo.setIsSuccess(e.getSuccess());
  295. pdfValuationRecordDo.setReason(e.getMsg());
  296. pdfValuationRecordDo.setCreatorId(0);
  297. pdfValuationRecordDo.setUpdaterId(0);
  298. pdfValuationRecordDo.setCreateTime(new Date());
  299. pdfValuationRecordDo.setUpdateTime(new Date());
  300. pdfValuationRecordDo.setIsvalid(1);
  301. return pdfValuationRecordDo;
  302. }).collect(Collectors.toList());
  303. }
  304. /**
  305. * 解析备案编码和备案编码
  306. *
  307. * @param headInfo excel第一行和第二行的内容,中间以'@'符号分隔
  308. * @return 备案编码和备案编码
  309. */
  310. public ParseValuationInfo parseRegisterNumAndFundName(String headInfo) {
  311. ParseValuationInfo info = new ParseValuationInfo();
  312. if (StringUtils.isNotEmpty(headInfo)) {
  313. List<String> contentList = Arrays.stream(headInfo.split("@")).collect(Collectors.toList());
  314. for (String content : contentList) {
  315. String registerNumber = content.length() > 6 ? content.substring(0, 6) : null;
  316. if (StrUtil.isNotBlank(registerNumber) && !ValuationDataUtils.hasChinese(registerNumber, false)) {
  317. info.setRegisterNumber(registerNumber);
  318. }
  319. if (content.contains("估值表") || content.contains("专用表")) {
  320. String originRegisterNumber = info.getRegisterNumber();
  321. String originFundName = info.getFundName();
  322. if (content.contains("___")) {
  323. List<String> collect = Arrays.stream(content.split("___")).collect(Collectors.toList());
  324. if (collect.size() == 4 && content.contains("专用表")) {
  325. info.setRegisterNumber(collect.get(1));
  326. info.setFundName(collect.get(2));
  327. } else {
  328. if (CollUtil.isNotEmpty(collect) && StrUtil.isBlank(originRegisterNumber) && !ValuationDataUtils.hasChinese(registerNumber, false)) {
  329. originRegisterNumber = collect.get(0);
  330. info.setRegisterNumber(originRegisterNumber);
  331. }
  332. originFundName = collect.size() == 2 ? collect.get(0) : originFundName;
  333. originFundName = collect.size() > 2 ? collect.get(1) : originFundName;
  334. info.setFundName(originFundName);
  335. }
  336. } else if (content.contains("__")) {
  337. List<String> collect = Arrays.stream(content.split("__")).collect(Collectors.toList());
  338. if (collect.size() == 4 && content.contains("专用表")) {
  339. info.setRegisterNumber(collect.get(1));
  340. info.setFundName(collect.get(2));
  341. } else {
  342. if (CollUtil.isNotEmpty(collect) && StrUtil.isBlank(originRegisterNumber) && !ValuationDataUtils.hasChinese(registerNumber, false)) {
  343. originRegisterNumber = collect.get(0);
  344. info.setRegisterNumber(originRegisterNumber);
  345. }
  346. originFundName = collect.size() == 2 ? collect.get(0) : originFundName;
  347. originFundName = collect.size() > 2 ? collect.get(1) : originFundName;
  348. info.setFundName(originFundName);
  349. }
  350. } else if (content.contains("_")) {
  351. List<String> collect = Arrays.stream(content.split("_")).collect(Collectors.toList());
  352. if (collect.size() == 4 && content.contains("专用表")) {
  353. info.setRegisterNumber(collect.get(1));
  354. info.setFundName(collect.get(2));
  355. } else {
  356. if (CollUtil.isNotEmpty(collect) && StrUtil.isBlank(originRegisterNumber) && !ValuationDataUtils.hasChinese(registerNumber, false)) {
  357. originRegisterNumber = collect.get(0);
  358. info.setRegisterNumber(originRegisterNumber);
  359. }
  360. originFundName = collect.size() == 2 ? collect.get(0) : originFundName;
  361. originFundName = collect.size() > 2 ? collect.get(1) : originFundName;
  362. info.setFundName(originFundName);
  363. }
  364. }
  365. }
  366. }
  367. }
  368. //兼容格式: xxx估值表@基金名称 -> 只能识别到基金名称
  369. if (StrUtil.isBlank(info.getFundName()) && StrUtil.isBlank(info.getRegisterNumber())) {
  370. List<String> contentList = Arrays.stream(headInfo.split("@")).collect(Collectors.toList());
  371. if (CollUtil.isNotEmpty(contentList) && contentList.size() >= 2) {
  372. String fundName = !contentList.get(1).contains("_") ? contentList.get(1) : null;
  373. info.setFundName(fundName);
  374. }
  375. }
  376. // 兼容格式:编码编码+基金名称+日期+估值报表四级 -> SXT974同增FOF稳增1期私募证券投资基金2024年08月02日估值报表四级
  377. if (StrUtil.isBlank(info.getFundName()) && StrUtil.isNotBlank(info.getRegisterNumber())) {
  378. int index = StrUtil.indexOfIgnoreCase(headInfo, "私募证券投资基金");
  379. // 说明找到了
  380. if (index != -1) {
  381. String shortName = headInfo.substring(0, StrUtil.indexOfIgnoreCase(headInfo, "私募证券投资基金"));
  382. String fundName = shortName.replace(info.getRegisterNumber(), "") + "私募证券投资基金";
  383. info.setFundName(fundName);
  384. }
  385. }
  386. return info;
  387. }
  388. public void saveFundPositionDetail(List<FundPositionDetailDO> fundPositionDetails, String fundId, String valuationDate) {
  389. int subBegin = 0;
  390. int subEnd = stepSize;
  391. int insertNum = 0;
  392. int hasStock = 0;
  393. int hasBond = 0;
  394. int hasFuture = 0;
  395. if (CollectionUtil.isNotEmpty(fundPositionDetails)) {
  396. //插入持仓数据 cm_fund_position_detail(记录数较多,得分批)
  397. // 先删除原先的数据 然后写入数据
  398. fundPositionDetailMapper.deleteUnUsed(fundId, valuationDate);
  399. // 将最终结果写入 cm_fund_position_detail
  400. while (subBegin < fundPositionDetails.size()) {
  401. List<FundPositionDetailDO> segment = fundPositionDetails.subList(subBegin, Math.min(subEnd, fundPositionDetails.size()));
  402. for (FundPositionDetailDO fundPositionDetail : segment) {
  403. //实收信托、实收资本对应的编码为107
  404. if (StrUtil.isNotBlank(fundPositionDetail.getSecuritiesName()) && "实收信托".equals(fundPositionDetail.getSecuritiesName().trim())) {
  405. fundPositionDetail.setSubjectCode("107");
  406. fundPositionDetail.setSecuritiesCode("107");
  407. }
  408. //设置创建者id,在拿取最近修改人时有用
  409. fundPositionDetail.setCreatorId(0);
  410. if (fundPositionDetail.getLevel() != null && fundPositionDetail.getLevel() >= 4) {
  411. Integer secType = fundPositionDetail.getSecType();
  412. Integer subType = fundPositionDetail.getSubType();
  413. if (secType != null && subType != null) {
  414. if (secType == HoldingType.Stock.getId() && subType == HoldingType.Stock.getId()) {
  415. hasStock = 1;
  416. }
  417. // 正逆回购不属于债券
  418. String subjectCode = fundPositionDetail.getSubjectCode();
  419. String[] SALE_CODES = {"2202", "1202"};
  420. if (secType == HoldingType.Bond.getId() && !StrUtil.containsAny(subjectCode, SALE_CODES)) {
  421. hasBond = 1;
  422. }
  423. if (secType == HoldingType.Future.getId() || secType == HoldingType.Option.getId()) {
  424. hasFuture = 1;
  425. }
  426. }
  427. }
  428. }
  429. insertNum += fundPositionDetailMapper.insertMulti(segment);
  430. subBegin = subEnd;
  431. subEnd += stepSize;
  432. }
  433. }
  434. // 更新 cm_user_valuation_table
  435. if (insertNum > 0) {
  436. valuationTableMapper.updateUpdateAnalyzed(fundId, valuationDate, hasStock, hasBond, hasFuture);
  437. }
  438. }
  439. public Integer trans2UserValuationDoAndWrite(AssetsValuationDetails details, String fundId, ValuationTableDO tableInfo, ValuationNeedParseParam valuationNeedParseParam) {
  440. valuationTableMapper.unValid(fundId, details.getValuationDate());
  441. tableInfo.setFundId(fundId);
  442. tableInfo.setValuationDate(DateUtil.StringToDate(details.getValuationDate()));
  443. tableInfo.setIsAnalyzed(0);
  444. tableInfo.setIsvalid(1);
  445. tableInfo.setCreateTime(DateTime.now());
  446. tableInfo.setUpdateTime(DateTime.now());
  447. tableInfo.setCreatorId(0);
  448. tableInfo.setUpdaterId(0);
  449. tableInfo.setTotalMarketValue(BigDecimalUtils.toBigDecimal(details.getTotalMarketValue()));
  450. tableInfo.setNetAssetsValue(BigDecimalUtils.toBigDecimal(details.getNetAssetsValue()));
  451. tableInfo.setIncrement(BigDecimalUtils.toBigDecimal(details.getIncrement()));
  452. tableInfo.setTitle(details.getTitle());
  453. tableInfo.setNav(BigDecimalUtils.toBigDecimal(details.getNav()));
  454. tableInfo.setFileUrl(valuationNeedParseParam.getFileUrl());
  455. tableInfo.setHeadInfo(details.getHeadInfo());
  456. tableInfo.setTailInfo(details.getTailInfo());
  457. tableInfo.setTableType(details.getType());
  458. tableInfo.setFromEmail(valuationNeedParseParam.getFromEmail());
  459. tableInfo.setOriginalFile(valuationNeedParseParam.getOriginFileName());
  460. tableInfo.setConvertedFile(valuationNeedParseParam.getFile().getName());
  461. valuationTableMapper.insert(tableInfo);
  462. return tableInfo.getId();
  463. }
  464. public AssetsValuationExcelInfo<AssetsValuationInfo> processDataV2(PreAssetsValuationInfo<PreAssetsValuationBase> info) {
  465. AssetsValuationExcelInfo<AssetsValuationInfo> avInfo = new AssetsValuationExcelInfo<>();
  466. AssetsValuationDetails extInfo = new AssetsValuationDetails();
  467. extInfo.setTailInfo(list2String(info.getFooter()));
  468. extInfo.setHeadInfo(list2String(info.getHeader().getHeaderList()));
  469. extInfo.setOriginalfile(info.getExcelOriginName());
  470. extInfo.setConvertedFile(info.getExcelNewName());
  471. extInfo.setFileUrl(info.getSavePath());
  472. extInfo.setTitle(info.getHeader().getTitle());
  473. extInfo.setType(info.getType().getId());
  474. extInfo.setNav(info.getHeader().getUnitNetValue());
  475. extInfo.setUserId(ValuationDataUtils.string2Int(info.getUserId()));
  476. extInfo.setValuationDate(new Date(info.getHeader().getValuationDate().getTime()));
  477. List<PreAssetsValuationBase> lBases = info.getData();
  478. ValuationDataUtils.removeUnderLine(lBases);
  479. List<AssetsValuationInfo> list = new ArrayList<>(lBases.size());
  480. //现在业务需要保存基金的总资产 总资产 资产净值 直接从解析结果获取
  481. Double totalMarketValue = null;
  482. // 总资产净值
  483. Double netAssetMarketValue = null;
  484. // 基金估值增值
  485. Double increment = null;
  486. // 资产份额
  487. Double assetShare = null;
  488. for (int i = 0; i < lBases.size(); i++) {
  489. PreAssetsValuationBase d = lBases.get(i);
  490. if (d.getSubjectCode() == null || d.getSubjectCode().isEmpty()) {
  491. continue;
  492. }
  493. String originalSubjectCode = d.getOriginalSubjectCode();
  494. if (ValuationDataUtils.checkMarketValue(originalSubjectCode)) {
  495. totalMarketValue = ValuationDataUtils.string2Double(d.getMarketValue());
  496. }
  497. if (ValuationDataUtils.checkAssetShare(originalSubjectCode)) {
  498. assetShare = ValuationDataUtils.string2Double(d.getMarketValue());
  499. }
  500. if (ValuationDataUtils.checkNetAssetsValue(originalSubjectCode)) {
  501. netAssetMarketValue = ValuationDataUtils.string2Double(d.getMarketValue());
  502. increment = ValuationDataUtils.string2Double(d.getValueAdded());
  503. }
  504. AssetsValuationInfo data = new AssetsValuationInfo();
  505. data.setUserId(ValuationDataUtils.string2Int(info.getUserId()));
  506. data.setSecuritiesAmount(ValuationDataUtils.string2Double(d.getAmount()));
  507. data.setHaltInfo(d.getSuspensionInfo());
  508. data.setIncrement(ValuationDataUtils.string2Double(d.getValueAdded()));
  509. data.setMarketValue(ValuationDataUtils.string2Double(d.getMarketValue()));
  510. data.setMarketValueRatio(ValuationDataUtils.string2Double(d.getRatioOfMarketValueToNetWorth()));
  511. data.setNetCost(ValuationDataUtils.string2Double(d.getCost()));
  512. data.setNetCostRatio(ValuationDataUtils.string2Double(d.getRatioOfCostToNetWorth()));
  513. data.setSubjectCode(d.getSubjectCode());
  514. data.setSecuritiesCode((d.getSecurtiesCode()));
  515. // 对于期权,如果以DR、XR开头,则剔除这两个字母
  516. if (data.getSubjectName() != null && (data.getSubjectName().startsWith("DR") || data.getSubjectName().startsWith("XR"))) {
  517. String subjectName = data.getSubjectName().replace("DR", "");
  518. data.setSubjectName(subjectName.replace("XR", ""));
  519. } else {
  520. data.setSubjectName(d.getSubjectName());
  521. }
  522. data.setUnitCost(ValuationDataUtils.string2Double(d.getUnitCost()));
  523. //寻找累计单位净值
  524. if (null == extInfo.getCumulativeNav()) {
  525. if (StringUtils.isNotEmpty(d.getSubjectCode()) && d.getSubjectCode().contains("累计单位净值")) {
  526. if (StringUtils.isNotEmpty(d.getSubjectName()) && ValuationDataUtils.isNumber(d.getSubjectName())) {
  527. extInfo.setCumulativeNav(Double.valueOf(d.getSubjectName()));
  528. }
  529. }
  530. }
  531. switch (d.getType()) {
  532. case GeneralTemplate:
  533. PreAssetsValuationGeneralTemplate general = (PreAssetsValuationGeneralTemplate) d;
  534. data.setOriginalSubjectCode(general.getOriginalSubjectCode());
  535. data.setMarketPrice(ValuationDataUtils.string2Double(general.getMarketPrice()));
  536. data.setCurrency(general.getCurrency());
  537. data.setExchangeRate(general.getExchangeRate());
  538. data.setOriCurrencyCost(ValuationDataUtils.string2Double(general.getOriCurrencyCost()));
  539. data.setOriCurrencyMarketValue(ValuationDataUtils.string2Double(general.getOriCurrencyMarketValue()));
  540. data.setOriCurrencyValueAdded(ValuationDataUtils.string2Double(general.getOriCurrencyValueAdded()));
  541. data.setSubjectLevel(general.getSubjectLevel());
  542. data.setIssuer(general.getIssuer());
  543. data.setVProjectCode(general.getvProjectCode());
  544. data.setVProjectName(general.getvProjectName());
  545. data.setCostRatioAsset(general.getCostRatioAsset());
  546. data.setMvRatioAsset(general.getMvRatioAsset());
  547. data.setSpotPrice(general.getSpotPrice());
  548. data.setRemark(general.getRemark());
  549. data.setRightsInterestsInfo(general.getRightAndInterestInfo());
  550. data.setAssumingCost(general.getAssumingCost());
  551. data.setHoldingState(general.getHoldingState());
  552. if (data.getSubjectName() != null && ValuationDataUtils.isValid(data.getSubjectCode())) {
  553. data.setSubjectCode(data.getSubjectCode().replace(".", ""));
  554. if (ValuationDataUtils.hasChinese(data.getSubjectCode(), false)) {
  555. String code = data.getSubjectCode().replace(data.getSubjectName(), "");
  556. code = ValuationDataUtils.getSubjectCode(code);
  557. if (code.length() >= 4) {
  558. data.setSubjectCode(code);
  559. } else {
  560. data.setSecType(100);
  561. }
  562. }
  563. }
  564. break;
  565. default:
  566. break;
  567. }
  568. list.add(data);
  569. }
  570. extInfo.setTotalMarketValue(totalMarketValue);
  571. extInfo.setAssetShare(assetShare);
  572. extInfo.setNetAssetsValue(netAssetMarketValue);
  573. extInfo.setIncrement(increment);
  574. avInfo.setExtInfo(extInfo);
  575. avInfo.setData(list);
  576. return avInfo;
  577. }
  578. private static String list2String(List<String> list) {
  579. if (CollUtil.isEmpty(list)) {
  580. return null;
  581. }
  582. return String.join("@", list);
  583. }
  584. }