|
@@ -0,0 +1,240 @@
|
|
|
+package com.simuwang.daq.components.report.parser.excel;
|
|
|
+
|
|
|
+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.common.exception.ReportParseException;
|
|
|
+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 java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.function.Function;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+@Component(ReportParserConstant.PARSER_EXCEL_ANNUALLY)
|
|
|
+public class ExcelAnnuallyReportParser extends AbstractExcelReportParser<AnnuallyReportData> {
|
|
|
+ public ExcelAnnuallyReportParser(EmailFieldMappingMapper fieldMappingMapper) {
|
|
|
+ super(fieldMappingMapper);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String getParser() {
|
|
|
+ return ReportParserConstant.PARSER_EXCEL_ANNUALLY;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected List<CustomExcelTable> customExcelTables() {
|
|
|
+ List<CustomExcelTable> customExcelTables = ListUtil.list(true);
|
|
|
+ customExcelTables.add(new CustomExcelTable("fundInfo", "基金基本情况", 2));
|
|
|
+ customExcelTables.add(new CustomExcelTable("fundInfo", "基金产品说明", 2, 4));
|
|
|
+ customExcelTables.add(new CustomExcelTable("financialIndicators", "主要会计数据和财务指标", 4));
|
|
|
+ customExcelTables.add(new CustomExcelTable("financialIndicators", "级基金主要会计数据和财务指标", 4, 10));
|
|
|
+ customExcelTables.add(new CustomExcelTable("assetAllocation", "期末基金资产组合情况", 3));
|
|
|
+ customExcelTables.add(new CustomExcelTable("investmentIndustry", "报告期末按行业分类的股票投资组合", 4));
|
|
|
+ customExcelTables.add(new CustomExcelTable("investmentIndustry", "报告期末按行业分类的港股通投资股票投资组合", 3));
|
|
|
+ customExcelTables.add(new CustomExcelTable("shareChange", "基金份额变动情况", 2, 6));
|
|
|
+ customExcelTables.add(new CustomExcelTable("shareChange", "级基金份额变动情况", 2, 6));
|
|
|
+ return customExcelTables;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected AnnuallyReportData parseExtInfoAndSetData(ReportBaseInfoDTO reportInfo, ReportFundInfoDTO reportFundInfo, List<SimpleTable> tables) {
|
|
|
+ Integer fileId = reportInfo.getFileId();
|
|
|
+ String reportName = reportInfo.getReportName();
|
|
|
+ // 主要财务指标
|
|
|
+ List<ReportFinancialIndicatorsDTO> financialIndicators = this.buildFinancialIndicatorsInfo(fileId, reportName, tables);
|
|
|
+ // 资产配置
|
|
|
+ List<ReportAssetAllocationDTO> assetAllocations = this.buildAssetAllocationInfo(fileId, reportName, tables);
|
|
|
+ // 行业配置
|
|
|
+ List<ReportInvestmentIndustryDTO> investmentIndustries = this.buildInvestmentIndustryInfo(fileId, reportName, tables);
|
|
|
+ // 份额变动
|
|
|
+ List<ReportShareChangeDTO> shareChanges = this.buildShareChangeInfo(fileId, reportName, tables);
|
|
|
+ // 构建返回结构
|
|
|
+ AnnuallyReportData reportData = new AnnuallyReportData(reportInfo, reportFundInfo);
|
|
|
+ reportData.setFinancialIndicators(financialIndicators);
|
|
|
+ reportData.setAssetAllocation(assetAllocations);
|
|
|
+ reportData.setInvestmentIndustry(investmentIndustries);
|
|
|
+ reportData.setShareChange(shareChanges);
|
|
|
+ return reportData;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected ReportFundInfoDTO buildFundInfo(ReportParserParams params, List<SimpleTable> tables) {
|
|
|
+ List<SimpleTable> simpleTables = tables.stream().filter(e -> "fundInfo".equals(e.getTableKey())).collect(Collectors.toList());
|
|
|
+ if (CollUtil.isEmpty(simpleTables)) {
|
|
|
+ throw new ReportParseException(ReportParseStatus.PARSE_FUND_INFO_FAIL, params.getFilename());
|
|
|
+ }
|
|
|
+ Map<String, Object> fundInfoMap = MapUtil.newHashMap(32);
|
|
|
+ for (SimpleTable table : simpleTables) {
|
|
|
+ Map<String, Object> baseInfoMap = MapUtil.newHashMap(32);
|
|
|
+ for (int i = 0; i < table.getTables().size(); i++) {
|
|
|
+ List<String> cols = table.getTables().get(i);
|
|
|
+ for (int j = 0; j < 1; j++) {
|
|
|
+ baseInfoMap.put(cols.get(j), cols.get(j + 1));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ fundInfoMap.putAll(baseInfoMap);
|
|
|
+ }
|
|
|
+ ReportFundInfoDTO info = new ReportFundInfoDTO(params.getFileId());
|
|
|
+ this.buildInfo(fundInfoMap, info);
|
|
|
+ return info;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建基金份额变动信息
|
|
|
+ *
|
|
|
+ * @param fileId 文件id
|
|
|
+ * @param filename 文件名称
|
|
|
+ * @param tables 所有表格
|
|
|
+ * @return /
|
|
|
+ */
|
|
|
+ private List<ReportShareChangeDTO> buildShareChangeInfo(Integer fileId, String filename, List<SimpleTable> tables) {
|
|
|
+ List<SimpleTable> simpleTables = tables.stream().filter(e -> "shareChange".equals(e.getTableKey())).collect(Collectors.toList());
|
|
|
+ if (CollUtil.isEmpty(simpleTables)) {
|
|
|
+ throw new ReportParseException(ReportParseStatus.PARSE_SHARE_INFO_FAIL, filename);
|
|
|
+ }
|
|
|
+ Function<SimpleTable, Map<String, Object>> function = t -> {
|
|
|
+ Map<String, Object> infoMap = MapUtil.newHashMap(16);
|
|
|
+ for (List<String> table : t.getTables()) {
|
|
|
+ String name = table.get(0);
|
|
|
+ if (name == null || !ReportParseUtils.SHARE_CHANGE_COLUMN_NAMES.contains(name)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ infoMap.put(name, table.get(1));
|
|
|
+ }
|
|
|
+ return infoMap;
|
|
|
+ };
|
|
|
+ return this.buildLevelDto(fileId, simpleTables, ReportShareChangeDTO.class, function);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建基金主要财务指标信息
|
|
|
+ *
|
|
|
+ * @param fileId 文件id
|
|
|
+ * @param filename 报告名称
|
|
|
+ * @param tables 所有表格
|
|
|
+ * @return /
|
|
|
+ */
|
|
|
+ private List<ReportFinancialIndicatorsDTO> buildFinancialIndicatorsInfo(Integer fileId, String filename, List<SimpleTable> tables) {
|
|
|
+ List<SimpleTable> simpleTables = tables.stream().filter(e -> "financialIndicators".equals(e.getTableKey())).collect(Collectors.toList());
|
|
|
+ if (CollUtil.isEmpty(simpleTables)) {
|
|
|
+ throw new ReportParseException(ReportParseStatus.PARSE_FINANCIAL_INFO_FAIL, filename);
|
|
|
+ }
|
|
|
+ List<ReportFinancialIndicatorsDTO> dtos = ListUtil.list(false);
|
|
|
+ // 分级基金
|
|
|
+ String titles = simpleTables.stream().map(SimpleTable::getTitle).collect(Collectors.joining(","));
|
|
|
+ List<String> levels = ReportParseUtils.matchTieredFund(titles);
|
|
|
+ // 存在分级基金
|
|
|
+ for (int k = 0; k < simpleTables.size(); k++) {
|
|
|
+ SimpleTable table = simpleTables.get(k);
|
|
|
+ int colCount = table.getColCount();
|
|
|
+ for (int j = 1; j < colCount; j++) {
|
|
|
+ Map<String, Object> infoMap = MapUtil.newHashMap(16);
|
|
|
+ String year = ReportParseUtils.cleaningValue(table.getCell(0, j));
|
|
|
+ infoMap.put("年度", year);
|
|
|
+ for (int i = 0; i < table.getRowCount(); i++) {
|
|
|
+ String columnName = ReportParseUtils.cleaningValue(table.getCell(i, 0));
|
|
|
+ if (!CollUtil.contains(ReportParseUtils.FINANCIAL_INDICATORS_COLUMN_NAMES, columnName)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ String value = ReportParseUtils.cleaningValue(table.getCell(i, j));
|
|
|
+ infoMap.put(columnName, value);
|
|
|
+ }
|
|
|
+ ReportFinancialIndicatorsDTO dto = new ReportFinancialIndicatorsDTO(fileId);
|
|
|
+ this.buildInfo(infoMap, dto);
|
|
|
+ dto.setLevel(levels.get(k));
|
|
|
+ dtos.add(dto);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return dtos;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建基金行业配置信息
|
|
|
+ *
|
|
|
+ * @param fileId 文件id
|
|
|
+ * @param filename 报告名称
|
|
|
+ * @param tables 所有表格
|
|
|
+ * @return /
|
|
|
+ */
|
|
|
+ private List<ReportInvestmentIndustryDTO> buildInvestmentIndustryInfo(Integer fileId, String filename, List<SimpleTable> tables) {
|
|
|
+ List<SimpleTable> simpleTables = tables.stream().filter(e -> "investmentIndustry".equals(e.getTableKey())).collect(Collectors.toList());
|
|
|
+ if (CollUtil.isEmpty(simpleTables)) {
|
|
|
+ throw new ReportParseException(ReportParseStatus.PARSE_INDUSTRY_INFO_FAIL, filename);
|
|
|
+ }
|
|
|
+ List<ReportInvestmentIndustryDTO> dtos = ListUtil.list(false);
|
|
|
+ for (SimpleTable table : simpleTables) {
|
|
|
+ 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 industryName = ReportParseUtils.cleaningValue(table.getCell(i, j));
|
|
|
+ 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)));
|
|
|
+ dto.setRatio(ReportParseUtils.cleaningValue(table.getCell(i, j + 2)));
|
|
|
+ dtos.add(dto);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return dtos;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建基金资产配置信息
|
|
|
+ *
|
|
|
+ * @param fileId 文件id
|
|
|
+ * @param filename 报告名称
|
|
|
+ * @param tables 所有表格
|
|
|
+ * @return /
|
|
|
+ */
|
|
|
+ private List<ReportAssetAllocationDTO> buildAssetAllocationInfo(Integer fileId, String filename, List<SimpleTable> tables) {
|
|
|
+ SimpleTable assetAllocationTable = tables.stream().filter(e -> "assetAllocation".equals(e.getTableKey())).findFirst().orElse(null);
|
|
|
+ if (assetAllocationTable == null) {
|
|
|
+ throw new ReportParseException(ReportParseStatus.PARSE_ASSET_INFO_FAIL, filename);
|
|
|
+ }
|
|
|
+ List<ReportAssetAllocationDTO> dtos = ListUtil.list(false);
|
|
|
+ // 按行遍历
|
|
|
+ for (List<String> row : assetAllocationTable.getTables()) {
|
|
|
+ String marketValueAndRemark = row.get(2);
|
|
|
+ String detail = row.get(1);
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+}
|