|
@@ -1,266 +1,289 @@
|
|
|
-//package com.smppw.modaq.infrastructure.components.report.parser.pdf;
|
|
|
-//
|
|
|
-//import cn.hutool.core.collection.CollUtil;
|
|
|
-//import cn.hutool.core.collection.ListUtil;
|
|
|
-//import cn.hutool.core.map.MapUtil;
|
|
|
-//import cn.hutool.core.util.StrUtil;
|
|
|
-//import com.simuwang.base.mapper.EmailFieldMappingMapper;
|
|
|
-//import com.simuwang.base.pojo.dto.report.*;
|
|
|
-//import com.simuwang.daq.components.ReportParseUtils;
|
|
|
-//import com.simuwang.daq.components.report.parser.ReportParserConstant;
|
|
|
-//import org.springframework.stereotype.Component;
|
|
|
-//import technology.tabula.RectangularTextContainer;
|
|
|
-//import technology.tabula.Table;
|
|
|
-//
|
|
|
-//import java.awt.geom.Rectangle2D;
|
|
|
-//import java.util.Comparator;
|
|
|
-//import java.util.List;
|
|
|
-//import java.util.Map;
|
|
|
-//import java.util.Set;
|
|
|
-//import java.util.function.Function;
|
|
|
-//
|
|
|
-///**
|
|
|
-// * @author wangzaijun
|
|
|
-// * @date 2024/9/29 17:53
|
|
|
-// * @description pdf格式的季报解析逻辑
|
|
|
-// */
|
|
|
-//@Component(ReportParserConstant.PARSER_PDF_QUARTERLY)
|
|
|
-//public class PDQuarterlyReportParser<T extends QuarterlyReportData> extends AbstractPDReportParser<T> {
|
|
|
-// protected List<Table> financialIndicatorsTables;
|
|
|
-// protected List<Table> shareChangeTables;
|
|
|
-// protected List<Table> assetAllocationTables;
|
|
|
-// protected List<Table> investmentIndustryTables;
|
|
|
-//
|
|
|
-// public PDQuarterlyReportParser(EmailFieldMappingMapper fieldMappingMapper) {
|
|
|
-// super(fieldMappingMapper);
|
|
|
-// }
|
|
|
-//
|
|
|
-// @Override
|
|
|
-// public String getParser() {
|
|
|
-// return ReportParserConstant.PARSER_PDF_QUARTERLY;
|
|
|
-// }
|
|
|
-//
|
|
|
-// @Override
|
|
|
-// protected void initTableInfo(List<Table> tables) {
|
|
|
-// this.financialIndicatorsTables = ListUtil.list(true);
|
|
|
-// this.shareChangeTables = ListUtil.list(true);
|
|
|
-// this.assetAllocationTables = ListUtil.list(true);
|
|
|
-// this.investmentIndustryTables = ListUtil.list(true);
|
|
|
-// for (Table table : tables) {
|
|
|
-// int colCount = table.getColCount();
|
|
|
-// int rowCount = table.getRowCount();
|
|
|
-// if (colCount == 0 && rowCount == 0) {
|
|
|
-// continue;
|
|
|
-// }
|
|
|
-// if (rowCount == 13 && colCount == 2) {
|
|
|
-// this.fundInfoTable = table;
|
|
|
-// } else if (colCount == 2) {
|
|
|
-// // 用表格的第一列的数据判断是否份额变动记录
|
|
|
-// List<String> texts = this.getTableColTexts(table, 0);
|
|
|
-// // 主要财务指标或份额变动
|
|
|
-// if (CollUtil.containsAny(texts, ReportParseUtils.SHARE_CHANGE_COLUMN_NAMES)) {
|
|
|
-// this.shareChangeTables.add(table);
|
|
|
-// } else if (CollUtil.containsAny(texts, ReportParseUtils.FINANCIAL_INDICATORS_COLUMN_NAMES)) {
|
|
|
-// this.financialIndicatorsTables.add(table);
|
|
|
-// }
|
|
|
-// } else if (colCount == 4) {
|
|
|
-// // 行业配置
|
|
|
-// this.investmentIndustryTables.add(table);
|
|
|
-// } else if (colCount == 3) {
|
|
|
-// // 用表格的第一列单元格判断是否资产配置表
|
|
|
-// List<String> texts = this.getTableColTexts(table, 0);
|
|
|
-// if (CollUtil.containsAny(texts, ReportParseUtils.INDUSTRY_COLUMN_NAMES)) {
|
|
|
-// this.investmentIndustryTables.add(table);
|
|
|
-// } else {
|
|
|
-// texts = this.getTableColTexts(table, 1);
|
|
|
-// Set<String> keys = ReportParseUtils.ASSET_ALLOCATION_TYPE_MAPPER.keySet();
|
|
|
-// if (CollUtil.containsAny(texts, keys)) {
|
|
|
-// this.assetAllocationTables.add(table);
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-//
|
|
|
-// @Override
|
|
|
-// protected Map<String, Object> parseFundInfo(Table fundInfoTable) {
|
|
|
-// // 季报和年报的基金基本信息是两列的表格
|
|
|
-// Map<String, Object> baseInfoMap = MapUtil.newHashMap(32);
|
|
|
-// for (int i = 0; i < fundInfoTable.getRows().size(); i++) {
|
|
|
-// @SuppressWarnings("all")
|
|
|
-// List<RectangularTextContainer> cols = fundInfoTable.getRows().get(i);
|
|
|
-// for (int j = 0; j < 1; j++) {
|
|
|
-// baseInfoMap.put(cols.get(j).getText(), cols.get(j + 1).getText());
|
|
|
-// }
|
|
|
-// }
|
|
|
-// return baseInfoMap;
|
|
|
-// }
|
|
|
-//
|
|
|
-// @Override
|
|
|
-// protected T parseExtInfoAndSetData(ReportBaseInfoDTO reportInfo, ReportFundInfoDTO fundInfo) {
|
|
|
-// Integer fileId = reportInfo.getFileId();
|
|
|
-// // 表格转换数据获取函数
|
|
|
-// Function<Table, Map<String, Object>> function = t -> {
|
|
|
-// Map<String, Object> extInfoMap = MapUtil.newHashMap(16);
|
|
|
-// for (int i = 0; i < t.getRowCount(); i++) {
|
|
|
-// String key = t.getCell(i, 0).getText();
|
|
|
-// String value = t.getCell(i, 1).getText();
|
|
|
-// extInfoMap.put(key, value);
|
|
|
-// }
|
|
|
-// return extInfoMap;
|
|
|
-// };
|
|
|
-// // 份额变动
|
|
|
-// List<ReportShareChangeDTO> shareChanges = this.buildLevelDto(fileId, this.shareChangeTables,
|
|
|
-// ReportShareChangeDTO.class, function);
|
|
|
-// // 主要财务指标
|
|
|
-// List<ReportFinancialIndicatorsDTO> financialIndicators = this.buildFinancialIndicatorsInfo(fileId, function);
|
|
|
-// // 资产配置
|
|
|
-// List<ReportAssetAllocationDTO> assetAllocations = this.buildAssetAllocationInfo(fileId);
|
|
|
-// // 行业配置
|
|
|
-// List<ReportInvestmentIndustryDTO> investmentIndustries = this.buildInvestmentIndustryInfo(fileId);
|
|
|
-// // 返回数据构建
|
|
|
-// return this.buildReportData(reportInfo, fundInfo, shareChanges, financialIndicators, assetAllocations, investmentIndustries);
|
|
|
-// }
|
|
|
-//
|
|
|
-// /**
|
|
|
-// * 主要财务指标数据构建(包括分级基金,并且一个表格可能跨页)
|
|
|
-// *
|
|
|
-// * @param fileId 文件id
|
|
|
-// * @param function 字段映射关系
|
|
|
-// * @return /
|
|
|
-// */
|
|
|
-// protected List<ReportFinancialIndicatorsDTO> buildFinancialIndicatorsInfo(Integer fileId, Function<Table, Map<String, Object>> function) {
|
|
|
-// return this.buildLevelDto(fileId, this.financialIndicatorsTables, ReportFinancialIndicatorsDTO.class, function);
|
|
|
-// }
|
|
|
-//
|
|
|
-// /**
|
|
|
-// * 子类重写,放在cast异常
|
|
|
-// *
|
|
|
-// * @param reportInfo 报告基本信息
|
|
|
-// * @param fundInfo 基金基本信息
|
|
|
-// * @param shareChanges 份额变动
|
|
|
-// * @param financialIndicators 基本财务指标
|
|
|
-// * @param assetAllocations 资产配置
|
|
|
-// * @param investmentIndustries 行业配置
|
|
|
-// * @return /
|
|
|
-// */
|
|
|
-// protected T buildReportData(ReportBaseInfoDTO reportInfo, ReportFundInfoDTO fundInfo,
|
|
|
-// List<ReportShareChangeDTO> shareChanges,
|
|
|
-// List<ReportFinancialIndicatorsDTO> financialIndicators,
|
|
|
-// List<ReportAssetAllocationDTO> assetAllocations,
|
|
|
-// List<ReportInvestmentIndustryDTO> investmentIndustries) {
|
|
|
-// QuarterlyReportData reportData = new QuarterlyReportData(reportInfo, fundInfo);
|
|
|
-// reportData.setShareChange(shareChanges);
|
|
|
-// reportData.setFinancialIndicators(financialIndicators);
|
|
|
-// reportData.setAssetAllocation(assetAllocations);
|
|
|
-// reportData.setInvestmentIndustry(investmentIndustries);
|
|
|
-// @SuppressWarnings("unchecked")
|
|
|
-// T t = (T) reportData;
|
|
|
-// return t;
|
|
|
-// }
|
|
|
-//
|
|
|
-// @Override
|
|
|
-// protected void cleaningReportData(T reportData) {
|
|
|
-// // todo 数据清洗
|
|
|
-// }
|
|
|
-//
|
|
|
-// /**
|
|
|
-// * 构建基金行业配置解析数据
|
|
|
-// *
|
|
|
-// * @return /
|
|
|
-// */
|
|
|
-// private List<ReportInvestmentIndustryDTO> buildInvestmentIndustryInfo(Integer fileId) {
|
|
|
-// List<ReportInvestmentIndustryDTO> dtos = ListUtil.list(false);
|
|
|
-// for (Table table : this.investmentIndustryTables) {
|
|
|
-// int colCount = table.getColCount();
|
|
|
-// // 投资地区: 1-境内, 2-港股通
|
|
|
-// int investType = colCount == 4 ? 1 : 2;
|
|
|
-// int j = colCount == 4 ? 1 : 0;
|
|
|
-// // 按行遍历
|
|
|
-// for (int i = 0; i < table.getRowCount(); i++) {
|
|
|
-// String text = ReportParseUtils.cleaningValue(table.getCell(i, 0).getText());
|
|
|
-// if (StrUtil.containsAny(text, "序号", "行业类别")) {
|
|
|
-// continue;
|
|
|
-// }
|
|
|
-// String industryName = ReportParseUtils.cleaningValue(table.getCell(i, j).getText());
|
|
|
-// if (StrUtil.isBlank(industryName) || !ReportParseUtils.INDUSTRY_COLUMN_NAMES.contains(industryName)) {
|
|
|
-// continue;
|
|
|
-// }
|
|
|
-// ReportInvestmentIndustryDTO dto = new ReportInvestmentIndustryDTO(fileId);
|
|
|
-// dto.setInvestType(investType);
|
|
|
-// dto.setIndustryName(industryName);
|
|
|
-// dto.setMarketValue(ReportParseUtils.cleaningValue(table.getCell(i, j + 1).getText()));
|
|
|
-// dto.setRatio(ReportParseUtils.cleaningValue(table.getCell(i, j + 2).getText()));
|
|
|
-// dtos.add(dto);
|
|
|
-// }
|
|
|
-// }
|
|
|
-// return dtos;
|
|
|
-// }
|
|
|
-//
|
|
|
-// /**
|
|
|
-// * 构建基金资产配置解析数据
|
|
|
-// *
|
|
|
-// * @param fileId 文件id
|
|
|
-// * @return /
|
|
|
-// */
|
|
|
-// private List<ReportAssetAllocationDTO> buildAssetAllocationInfo(Integer fileId) {
|
|
|
-// List<ReportAssetAllocationDTO> dtos = ListUtil.list(false);
|
|
|
-// for (Table table : this.assetAllocationTables) {
|
|
|
-// // 按行遍历
|
|
|
-// for (@SuppressWarnings("all") List<RectangularTextContainer> row : table.getRows()) {
|
|
|
-// // x坐标升序(防止部分行乱序问题)
|
|
|
-// row.sort(Comparator.comparing(Rectangle2D.Float::getX));
|
|
|
-// // 金额、市值,有时是 “备注#金额”的格式
|
|
|
-// String marketValueAndRemark = ReportParseUtils.cleaningValue(row.get(2).getText());
|
|
|
-// // 资产明细
|
|
|
-// String detail = ReportParseUtils.cleaningValue(row.get(1).getText(), false);
|
|
|
-// if (!ReportParseUtils.ASSET_ALLOCATION_TYPE_MAPPER.containsKey(detail)) {
|
|
|
-// continue;
|
|
|
-// }
|
|
|
-// // 大类
|
|
|
-// String assetType = ReportParseUtils.ASSET_ALLOCATION_TYPE_MAPPER.get(detail);
|
|
|
-// if (StrUtil.contains(marketValueAndRemark, "#")) {
|
|
|
-// // 有#表示有备注,而且可能有多个,多个用分号分隔的.
|
|
|
-// List<String> marketValueAndRemarks = StrUtil.split(marketValueAndRemark, ";");
|
|
|
-// for (String mr : marketValueAndRemarks) {
|
|
|
-// if (StrUtil.isBlank(mr)) {
|
|
|
-// continue;
|
|
|
-// }
|
|
|
-// List<String> mrs = StrUtil.split(mr, "#");
|
|
|
-// ReportAssetAllocationDTO dto = new ReportAssetAllocationDTO(fileId);
|
|
|
-// dto.setAssetType(assetType);
|
|
|
-// dto.setAssetDetails(detail);
|
|
|
-// dto.setMarketValue(mrs.get(1));
|
|
|
-// dto.setRemark(mrs.get(0));
|
|
|
-// dtos.add(dto);
|
|
|
-// }
|
|
|
-// } else {
|
|
|
-// ReportAssetAllocationDTO dto = new ReportAssetAllocationDTO(fileId);
|
|
|
-// dto.setAssetType(assetType);
|
|
|
-// dto.setAssetDetails(detail);
|
|
|
-// dto.setMarketValue(marketValueAndRemark);
|
|
|
-// dtos.add(dto);
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-// return dtos;
|
|
|
-// }
|
|
|
-//
|
|
|
-// /**
|
|
|
-// * 获取表格指定列的所有文字内容
|
|
|
-// *
|
|
|
-// * @param table 表格
|
|
|
-// * @param col 指定列
|
|
|
-// * @return /
|
|
|
-// */
|
|
|
-// protected List<String> getTableColTexts(Table table, Integer col) {
|
|
|
-// List<String> details = ListUtil.list(false);
|
|
|
-// for (@SuppressWarnings("all") List<RectangularTextContainer> row : table.getRows()) {
|
|
|
-// String detail = ReportParseUtils.cleaningValue(row.get(col).getText(), false);
|
|
|
-// if (StrUtil.isNotBlank(detail)) {
|
|
|
-// details.add(detail);
|
|
|
-// }
|
|
|
-// }
|
|
|
-// return details;
|
|
|
-// }
|
|
|
-//}
|
|
|
+package com.smppw.modaq.application.components.report.parser.pdf;
|
|
|
+
|
|
|
+import cn.hutool.core.collection.CollUtil;
|
|
|
+import cn.hutool.core.collection.ListUtil;
|
|
|
+import cn.hutool.core.map.MapUtil;
|
|
|
+import cn.hutool.core.util.StrUtil;
|
|
|
+import com.smppw.modaq.application.components.ReportParseUtils;
|
|
|
+import com.smppw.modaq.application.components.report.parser.ReportParserConstant;
|
|
|
+import com.smppw.modaq.common.enums.ReportParseStatus;
|
|
|
+import com.smppw.modaq.common.exception.ReportParseException;
|
|
|
+import com.smppw.modaq.domain.dto.report.*;
|
|
|
+import com.smppw.modaq.domain.mapper.EmailFieldMappingMapper;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+import technology.tabula.RectangularTextContainer;
|
|
|
+import technology.tabula.Table;
|
|
|
+
|
|
|
+import java.awt.geom.Rectangle2D;
|
|
|
+import java.util.Comparator;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Set;
|
|
|
+import java.util.function.Function;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @author wangzaijun
|
|
|
+ * @date 2024/9/29 17:53
|
|
|
+ * @description pdf格式的季报解析逻辑
|
|
|
+ */
|
|
|
+@Component(ReportParserConstant.PARSER_PDF_QUARTERLY)
|
|
|
+public class PDQuarterlyReportParser<T extends QuarterlyReportData> extends AbstractPDReportParser<T> {
|
|
|
+ protected Table fundInfoTable;
|
|
|
+ protected List<Table> financialIndicatorsTables;
|
|
|
+ protected List<Table> shareChangeTables;
|
|
|
+ protected List<Table> assetAllocationTables;
|
|
|
+ protected List<Table> investmentIndustryTables;
|
|
|
+
|
|
|
+ public PDQuarterlyReportParser(EmailFieldMappingMapper fieldMappingMapper) {
|
|
|
+ super(fieldMappingMapper);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String getParser() {
|
|
|
+ return ReportParserConstant.PARSER_PDF_QUARTERLY;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void init() {
|
|
|
+ super.init();
|
|
|
+ this.fundInfoTable = null;
|
|
|
+ this.financialIndicatorsTables = ListUtil.list(true);
|
|
|
+ this.shareChangeTables = ListUtil.list(true);
|
|
|
+ this.assetAllocationTables = ListUtil.list(true);
|
|
|
+ this.investmentIndustryTables = ListUtil.list(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void initTableInfo(List<Table> tables) {
|
|
|
+ Map<Integer, List<Table>> spanningPageFinancialIndicatorsTableMap = MapUtil.newHashMap(8, true);
|
|
|
+ Map<Integer, List<Table>> spanningPageShareChangeTableMap = MapUtil.newHashMap(8, true);
|
|
|
+ int fi = 0;
|
|
|
+ int sci = 0;
|
|
|
+ for (Table table : tables) {
|
|
|
+ int colCount = table.getColCount();
|
|
|
+ int rowCount = table.getRowCount();
|
|
|
+ if (colCount == 0 && rowCount == 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (rowCount == 13 && colCount == 2) {
|
|
|
+ this.fundInfoTable = table;
|
|
|
+ } else if (colCount == 2) {
|
|
|
+ // 用表格的第一列的数据判断是否份额变动记录
|
|
|
+ List<String> texts = this.getTableColTexts(table, 0);
|
|
|
+ // 主要财务指标或份额变动
|
|
|
+ if (CollUtil.containsAny(texts, ReportParseUtils.SHARE_CHANGE_COLUMN_NAMES)) {
|
|
|
+ sci = this.splitTables(table, 5, sci, this.shareChangeTables, spanningPageShareChangeTableMap);
|
|
|
+ } else if (CollUtil.containsAny(texts, ReportParseUtils.FINANCIAL_INDICATORS_COLUMN_NAMES)) {
|
|
|
+ fi = this.splitTables(table, 10, fi, this.financialIndicatorsTables, spanningPageFinancialIndicatorsTableMap);
|
|
|
+ }
|
|
|
+ } else if (colCount == 4) {
|
|
|
+ // 行业配置
|
|
|
+ this.investmentIndustryTables.add(table);
|
|
|
+ } else if (colCount == 3) {
|
|
|
+ // 用表格的第一列单元格判断是否资产配置表
|
|
|
+ List<String> texts = this.getTableColTexts(table, 0);
|
|
|
+ if (CollUtil.containsAny(texts, ReportParseUtils.INDUSTRY_COLUMN_NAMES)) {
|
|
|
+ this.investmentIndustryTables.add(table);
|
|
|
+ } else {
|
|
|
+ texts = this.getTableColTexts(table, 1);
|
|
|
+ Set<String> keys = ReportParseUtils.ASSET_ALLOCATION_TYPE_MAPPER.keySet();
|
|
|
+ if (CollUtil.containsAny(texts, keys)) {
|
|
|
+ this.assetAllocationTables.add(table);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 跨页的财务信息记录表(包括表头一共有10行)
|
|
|
+ this.handleSpanningPageTables(this.financialIndicatorsTables, spanningPageFinancialIndicatorsTableMap);
|
|
|
+ // 跨页的份额变动记录表(包括表头一共有5行)
|
|
|
+ this.handleSpanningPageTables(this.shareChangeTables, spanningPageShareChangeTableMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected ReportFundInfoDTO buildFundInfo(ReportParserParams params) {
|
|
|
+ Table fundInfoTable = this.fundInfoTable;
|
|
|
+ if (fundInfoTable == null) {
|
|
|
+ throw new ReportParseException(ReportParseStatus.PARSE_FUND_INFO_FAIL, params.getFilename());
|
|
|
+ }
|
|
|
+ // 基金基本信息映射
|
|
|
+ Map<String, Object> extInfoMap = this.parseFundInfo(fundInfoTable);
|
|
|
+ return this.buildDto(params.getFileId(), ReportFundInfoDTO.class, extInfoMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ protected Map<String, Object> parseFundInfo(Table fundInfoTable) {
|
|
|
+ // 季报和年报的基金基本信息是两列的表格
|
|
|
+ Map<String, Object> baseInfoMap = MapUtil.newHashMap(32);
|
|
|
+ for (int i = 0; i < fundInfoTable.getRows().size(); i++) {
|
|
|
+ @SuppressWarnings("all")
|
|
|
+ List<RectangularTextContainer> cols = fundInfoTable.getRows().get(i);
|
|
|
+ for (int j = 0; j < 1; j++) {
|
|
|
+ String key = ReportParseUtils.cleaningValue(cols.get(j).getText());
|
|
|
+ baseInfoMap.put(key, cols.get(j + 1).getText());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return baseInfoMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected T parseExtInfoAndSetData(ReportBaseInfoDTO reportInfo, ReportFundInfoDTO fundInfo) {
|
|
|
+ Integer fileId = reportInfo.getFileId();
|
|
|
+ // 表格转换数据获取函数
|
|
|
+ Function<Table, Map<String, Object>> function = t -> {
|
|
|
+ Map<String, Object> extInfoMap = MapUtil.newHashMap(16);
|
|
|
+ for (int i = 0; i < t.getRowCount(); i++) {
|
|
|
+ String key = ReportParseUtils.cleaningValue(t.getCell(i, 0).getText());
|
|
|
+ String value = t.getCell(i, 1).getText();
|
|
|
+ extInfoMap.put(key, value);
|
|
|
+ }
|
|
|
+ return extInfoMap;
|
|
|
+ };
|
|
|
+ // 份额变动
|
|
|
+ List<ReportShareChangeDTO> shareChanges = this.buildLevelDto(fileId, this.shareChangeTables,
|
|
|
+ ReportShareChangeDTO.class, function);
|
|
|
+ // 主要财务指标
|
|
|
+ List<ReportFinancialIndicatorsDTO> financialIndicators = this.buildFinancialIndicatorsInfo(fileId, function);
|
|
|
+ // 资产配置
|
|
|
+ List<ReportAssetAllocationDTO> assetAllocations = this.buildAssetAllocationInfo(fileId);
|
|
|
+ // 行业配置
|
|
|
+ List<ReportInvestmentIndustryDTO> investmentIndustries = this.buildInvestmentIndustryInfo(fileId);
|
|
|
+ // 返回数据构建
|
|
|
+ return this.buildReportData(reportInfo, fundInfo, shareChanges, financialIndicators, assetAllocations, investmentIndustries);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 主要财务指标数据构建(包括分级基金,并且一个表格可能跨页)
|
|
|
+ *
|
|
|
+ * @param fileId 文件id
|
|
|
+ * @param function 字段映射关系
|
|
|
+ * @return /
|
|
|
+ */
|
|
|
+ protected List<ReportFinancialIndicatorsDTO> buildFinancialIndicatorsInfo(Integer fileId,
|
|
|
+ Function<Table, Map<String, Object>> function) {
|
|
|
+ return this.buildLevelDto(fileId, this.financialIndicatorsTables, ReportFinancialIndicatorsDTO.class, function);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 子类重写,放在cast异常
|
|
|
+ *
|
|
|
+ * @param reportInfo 报告基本信息
|
|
|
+ * @param fundInfo 基金基本信息
|
|
|
+ * @param shareChanges 份额变动
|
|
|
+ * @param financialIndicators 基本财务指标
|
|
|
+ * @param assetAllocations 资产配置
|
|
|
+ * @param investmentIndustries 行业配置
|
|
|
+ * @return /
|
|
|
+ */
|
|
|
+ protected T buildReportData(ReportBaseInfoDTO reportInfo, ReportFundInfoDTO fundInfo,
|
|
|
+ List<ReportShareChangeDTO> shareChanges,
|
|
|
+ List<ReportFinancialIndicatorsDTO> financialIndicators,
|
|
|
+ List<ReportAssetAllocationDTO> assetAllocations,
|
|
|
+ List<ReportInvestmentIndustryDTO> investmentIndustries) {
|
|
|
+ QuarterlyReportData reportData = new QuarterlyReportData(reportInfo, fundInfo);
|
|
|
+ reportData.setShareChange(shareChanges);
|
|
|
+ reportData.setFinancialIndicators(financialIndicators);
|
|
|
+ reportData.setAssetAllocation(assetAllocations);
|
|
|
+ reportData.setInvestmentIndustry(investmentIndustries);
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ T t = (T) reportData;
|
|
|
+ return t;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建基金行业配置解析数据
|
|
|
+ *
|
|
|
+ * @return /
|
|
|
+ */
|
|
|
+ private List<ReportInvestmentIndustryDTO> buildInvestmentIndustryInfo(Integer fileId) {
|
|
|
+ List<ReportInvestmentIndustryDTO> dtos = ListUtil.list(false);
|
|
|
+ for (Table table : this.investmentIndustryTables) {
|
|
|
+ int colCount = table.getColCount();
|
|
|
+ // 投资地区: 1-境内, 2-港股通
|
|
|
+ int investType = colCount == 4 ? 1 : 2;
|
|
|
+ int j = colCount == 4 ? 1 : 0;
|
|
|
+ // 按行遍历
|
|
|
+ for (int i = 0; i < table.getRowCount(); i++) {
|
|
|
+ String text = ReportParseUtils.cleaningValue(table.getCell(i, 0).getText());
|
|
|
+ if (StrUtil.containsAny(text, "序号", "行业类别")) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ String industryName = ReportParseUtils.cleaningValue(table.getCell(i, j).getText());
|
|
|
+ if (StrUtil.isBlank(industryName) || !ReportParseUtils.INDUSTRY_COLUMN_NAMES.contains(industryName)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ ReportInvestmentIndustryDTO dto = new ReportInvestmentIndustryDTO(fileId);
|
|
|
+ dto.setInvestType(investType);
|
|
|
+ dto.setIndustryName(industryName);
|
|
|
+ dto.setMarketValue(ReportParseUtils.cleaningValue(table.getCell(i, j + 1).getText()));
|
|
|
+ dto.setRatio(ReportParseUtils.cleaningValue(table.getCell(i, j + 2).getText()));
|
|
|
+ dtos.add(dto);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return dtos;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建基金资产配置解析数据
|
|
|
+ *
|
|
|
+ * @param fileId 文件id
|
|
|
+ * @return /
|
|
|
+ */
|
|
|
+ private List<ReportAssetAllocationDTO> buildAssetAllocationInfo(Integer fileId) {
|
|
|
+ List<ReportAssetAllocationDTO> dtos = ListUtil.list(false);
|
|
|
+ for (Table table : this.assetAllocationTables) {
|
|
|
+ // 按行遍历
|
|
|
+ for (@SuppressWarnings("all") List<RectangularTextContainer> row : table.getRows()) {
|
|
|
+ // x坐标升序(防止部分行乱序问题)
|
|
|
+ row.sort(Comparator.comparing(Rectangle2D.Float::getX));
|
|
|
+ // 金额、市值,有时是 “备注#金额”的格式
|
|
|
+ String marketValueAndRemark = ReportParseUtils.cleaningValue(row.get(2).getText());
|
|
|
+ // 资产明细
|
|
|
+ String detail = ReportParseUtils.cleaningValue(row.get(1).getText(), false);
|
|
|
+ if (!ReportParseUtils.ASSET_ALLOCATION_TYPE_MAPPER.containsKey(detail)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 大类
|
|
|
+ String assetType = ReportParseUtils.ASSET_ALLOCATION_TYPE_MAPPER.get(detail);
|
|
|
+ if (StrUtil.contains(marketValueAndRemark, "#")) {
|
|
|
+ // 有#表示有备注,而且可能有多个,多个用分号分隔的.
|
|
|
+ List<String> marketValueAndRemarks = StrUtil.split(marketValueAndRemark, ";");
|
|
|
+ for (String mr : marketValueAndRemarks) {
|
|
|
+ if (StrUtil.isBlank(mr)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ List<String> mrs = StrUtil.split(mr, "#");
|
|
|
+ ReportAssetAllocationDTO dto = new ReportAssetAllocationDTO(fileId);
|
|
|
+ dto.setAssetType(assetType);
|
|
|
+ dto.setAssetDetails(detail);
|
|
|
+ dto.setMarketValue(mrs.get(1));
|
|
|
+ dto.setRemark(mrs.get(0));
|
|
|
+ dtos.add(dto);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ ReportAssetAllocationDTO dto = new ReportAssetAllocationDTO(fileId);
|
|
|
+ dto.setAssetType(assetType);
|
|
|
+ dto.setAssetDetails(detail);
|
|
|
+ dto.setMarketValue(marketValueAndRemark);
|
|
|
+ dtos.add(dto);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return dtos;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取表格指定列的所有文字内容
|
|
|
+ *
|
|
|
+ * @param table 表格
|
|
|
+ * @param col 指定列
|
|
|
+ * @return /
|
|
|
+ */
|
|
|
+ protected List<String> getTableColTexts(Table table, Integer col) {
|
|
|
+ List<String> details = ListUtil.list(false);
|
|
|
+ for (@SuppressWarnings("all") List<RectangularTextContainer> row : table.getRows()) {
|
|
|
+ String detail = ReportParseUtils.cleaningValue(row.get(col).getText(), false);
|
|
|
+ if (StrUtil.isNotBlank(detail)) {
|
|
|
+ details.add(detail);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return details;
|
|
|
+ }
|
|
|
+}
|