From 8cee271b80b48d1d8af44111022bf0e08ad245b5 Mon Sep 17 00:00:00 2001 From: AlkesandrKlimchuk <1Vipe234@gmail.com> Date: Tue, 25 Apr 2023 21:50:55 +0300 Subject: [PATCH 1/2] add finam classes --- .../parser/finam/FinamBrokerReport.java | 93 ++++++++++++++++ .../finam/FinamBrokerReportFactory.java | 64 +++++++++++ .../finam/FinamPortfolioPropertyTable.java | 104 ++++++++++++++++++ .../parser/finam/FinamReportTables.java | 77 +++++++++++++ .../finam/FinamReportTablesFactory.java | 39 +++++++ 5 files changed, 377 insertions(+) create mode 100644 src/main/java/ru/investbook/parser/finam/FinamBrokerReport.java create mode 100644 src/main/java/ru/investbook/parser/finam/FinamBrokerReportFactory.java create mode 100644 src/main/java/ru/investbook/parser/finam/FinamPortfolioPropertyTable.java create mode 100644 src/main/java/ru/investbook/parser/finam/FinamReportTables.java create mode 100644 src/main/java/ru/investbook/parser/finam/FinamReportTablesFactory.java diff --git a/src/main/java/ru/investbook/parser/finam/FinamBrokerReport.java b/src/main/java/ru/investbook/parser/finam/FinamBrokerReport.java new file mode 100644 index 00000000..f5d5cd42 --- /dev/null +++ b/src/main/java/ru/investbook/parser/finam/FinamBrokerReport.java @@ -0,0 +1,93 @@ +/* + * InvestBook + * Copyright (C) 2023 Spacious Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package ru.investbook.parser.finam; + +import lombok.EqualsAndHashCode; +import org.apache.poi.ss.usermodel.Workbook; +import org.spacious_team.table_wrapper.api.ReportPage; +import org.spacious_team.table_wrapper.api.TableCellAddress; +import org.spacious_team.table_wrapper.excel.ExcelSheet; +import ru.investbook.parser.AbstractExcelBrokerReport; +import ru.investbook.parser.SecurityRegistrar; + +import java.io.InputStream; +import java.nio.file.Paths; +import java.time.Instant; +import java.time.temporal.ChronoUnit; + +@EqualsAndHashCode(callSuper = true) +public class FinamBrokerReport extends AbstractExcelBrokerReport { + + @SuppressWarnings("UnnecessaryUnicodeEscape") + private static final String UNIQ_TEXT = "Акционерное общество \u00ABИнвестиционная компания \u00ABФИНАМ\u00BB"; + private static final String PORTFOLIO_MARKER = "По счету:"; + private static final String REPORT_END_DATE_MARKER = "Справка о состоянии обязательств"; + private static final int REPORT_END_DATE_POSITION = 9; + + private final Workbook book; + + public FinamBrokerReport(String excelFileName, InputStream is, SecurityRegistrar securityRegistrar) { + super(securityRegistrar); + this.book = getWorkBook(excelFileName, is); + final ReportPage reportPage = new ExcelSheet(book.getSheetAt(0)); + checkReportFormat(excelFileName, reportPage); + setPath(Paths.get(excelFileName)); + setReportPage(reportPage); + setPortfolio(getPortfolio(reportPage)); + setReportEndDateTime(getReportEndDateTime(reportPage)); + } + + private String getPortfolio(ReportPage reportPage) { + try { + return String.valueOf(reportPage.getNextColumnValue(PORTFOLIO_MARKER)); + } catch (Exception e) { + // TODO: Дейсствительно ли тут влетает исключение? + throw new IllegalArgumentException( + "В отчете не найден номер договора по заданному шаблону '" + PORTFOLIO_MARKER + "' XXX" + ); + } + } + + private Instant getReportEndDateTime(ReportPage reportPage) { + try { + final TableCellAddress address = reportPage.findByPrefix(REPORT_END_DATE_MARKER, 0, 1); + @SuppressWarnings("DataFlowIssue") + final String value = reportPage.getCell(address) + .getStringValue() + .split(" ")[REPORT_END_DATE_POSITION]; + return convertToInstant(value) + .plus(LAST_TRADE_HOUR, ChronoUnit.HOURS); + } catch (Exception e) { + throw new IllegalArgumentException( + "Не найдена дата отчета по заданному шаблону '" + REPORT_END_DATE_MARKER+ " XXX'" + ); + } + } + + public static void checkReportFormat(String excelFileName, ReportPage reportPage) { + if (reportPage.findByPrefix(UNIQ_TEXT, 2) == TableCellAddress.NOT_FOUND) { + throw new RuntimeException("В файле " + excelFileName + " не содежится отчета брокера ФИНАМ"); + } + } + + @Override + public void close() throws Exception { + this.book.close(); + } +} diff --git a/src/main/java/ru/investbook/parser/finam/FinamBrokerReportFactory.java b/src/main/java/ru/investbook/parser/finam/FinamBrokerReportFactory.java new file mode 100644 index 00000000..a608ab6f --- /dev/null +++ b/src/main/java/ru/investbook/parser/finam/FinamBrokerReportFactory.java @@ -0,0 +1,64 @@ +/* + * InvestBook + * Copyright (C) 2023 Spacious Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package ru.investbook.parser.finam; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.spacious_team.broker.report_parser.api.AbstractBrokerReportFactory; +import org.spacious_team.broker.report_parser.api.BrokerReport; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import ru.investbook.parser.SecurityRegistrar; + +import java.io.InputStream; +import java.util.Optional; +import java.util.regex.Pattern; + +@Component +@Order(Ordered.HIGHEST_PRECEDENCE) // TODO:why??? +@Slf4j +@RequiredArgsConstructor +public class FinamBrokerReportFactory extends AbstractBrokerReportFactory { + + private final SecurityRegistrar securityRegistrar; + + @Getter + private final String brokerName = "ФИНАМ"; + + private final Pattern expectedFileNamePattern = Pattern.compile( + "^(\\p{L}+_){3}КлФ_[0-9]+_\\d{2}_\\d{2}_\\d{4}_по_\\d{2}_\\d{2}_\\d{4}\\.xls(x)?$" + ); + + @Override + public boolean canCreate(String excelFileName, InputStream is) { + return super.canCreate(expectedFileNamePattern, excelFileName, is); + } + + @Override + public Optional create(String excelFileName, InputStream is) { + Optional brokerReport = create(excelFileName, is, + (fileName, stream) -> new FinamBrokerReport(fileName, stream, securityRegistrar)); + if (brokerReport.isPresent()) { + log.info("Обнаружен отчет '{}' Финам брокера", excelFileName); + } + return brokerReport; + } +} diff --git a/src/main/java/ru/investbook/parser/finam/FinamPortfolioPropertyTable.java b/src/main/java/ru/investbook/parser/finam/FinamPortfolioPropertyTable.java new file mode 100644 index 00000000..bcb8293b --- /dev/null +++ b/src/main/java/ru/investbook/parser/finam/FinamPortfolioPropertyTable.java @@ -0,0 +1,104 @@ +/* + * InvestBook + * Copyright (C) 2023 Spacious Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package ru.investbook.parser.finam; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.spacious_team.broker.pojo.PortfolioProperty; +import org.spacious_team.broker.pojo.PortfolioPropertyType; +import org.spacious_team.broker.report_parser.api.BrokerReport; +import org.spacious_team.table_wrapper.api.ConstantPositionTableColumn; +import org.spacious_team.table_wrapper.api.PatternTableColumn; +import org.spacious_team.table_wrapper.api.Table; +import org.spacious_team.table_wrapper.api.TableColumn; +import org.spacious_team.table_wrapper.api.TableHeaderColumn; +import org.spacious_team.table_wrapper.api.TableRow; +import ru.investbook.parser.SingleBrokerReport; +import ru.investbook.parser.SingleInitializableReportTable; + +import java.util.Collection; +import java.util.Collections; + +@Slf4j +public class FinamPortfolioPropertyTable extends SingleInitializableReportTable { + + private static final String SUMMARY_TABLE = "1. Оценка состояния счета Клиента"; + private static final String ASSETS = "ИТОГО оценка состояния счета (руб.)"; + + public FinamPortfolioPropertyTable(SingleBrokerReport report) { + super(report); + } + + @Override + protected Collection parseTable() { + final Table table = getSummaryTable(); + return getTotalAssets(table); + } + + protected Table getSummaryTable() { + return getSummaryTable(getReport(), ASSETS); + } + + public static Table getSummaryTable(BrokerReport report, String tableFooterString) { + final Table table = report.getReportPage() + .createNameless("На начало периода", tableFooterString, FinamSummaryTableHeader.class); + if (table.isEmpty()) { + throw new IllegalArgumentException("Таблица '" + SUMMARY_TABLE + "' не найдена"); + } + return table; + } + + protected Collection getTotalAssets(Table table) { + try { + final TableRow row = table.findRowByPrefix(ASSETS); + if (row == null) { + return Collections.emptyList(); + } + return Collections.singletonList(PortfolioProperty.builder() + .portfolio(getReport().getPortfolio()) + .property(PortfolioPropertyType.TOTAL_ASSETS_RUB) + .value(row.getBigDecimalCellValue(FinamSummaryTableHeader.PERIOD_END).toString()) + .timestamp(getReport().getReportEndDateTime()) + .build() + ); + } catch (Exception e) { + log.info("Не могу получить стоимость активов из отчета {}", getReport()); + return Collections.emptyList(); + } + } + + @RequiredArgsConstructor + private enum FinamSummaryTableHeader implements TableHeaderColumn { + DESCRIPTION(ConstantPositionTableColumn.of(0)), + PERIOD_BEGIN(PatternTableColumn.of(HeaderDescriptions.PERIOD_BEGIN_HEADER)), + PERIOD_END(PatternTableColumn.of(HeaderDescriptions.PERIOD_END_HEADER)), + PERIOD_CHANGE(PatternTableColumn.of(HeaderDescriptions.PERIOD_CHANGE_HEADER)); + + @Getter + private final TableColumn column; + + private static class HeaderDescriptions { + private static final String PERIOD_BEGIN_HEADER = "На начало периода"; + private static final String PERIOD_END_HEADER = "На конец периода"; + private static final String PERIOD_CHANGE_HEADER = "Изменение за период"; + } + + } +} diff --git a/src/main/java/ru/investbook/parser/finam/FinamReportTables.java b/src/main/java/ru/investbook/parser/finam/FinamReportTables.java new file mode 100644 index 00000000..265bd383 --- /dev/null +++ b/src/main/java/ru/investbook/parser/finam/FinamReportTables.java @@ -0,0 +1,77 @@ +/* + * InvestBook + * Copyright (C) 2023 Spacious Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package ru.investbook.parser.finam; + +import org.spacious_team.broker.pojo.EventCashFlow; +import org.spacious_team.broker.pojo.ForeignExchangeRate; +import org.spacious_team.broker.pojo.PortfolioCash; +import org.spacious_team.broker.pojo.PortfolioProperty; +import org.spacious_team.broker.pojo.Security; +import org.spacious_team.broker.pojo.SecurityEventCashFlow; +import org.spacious_team.broker.pojo.SecurityQuote; +import org.spacious_team.broker.report_parser.api.AbstractReportTables; +import org.spacious_team.broker.report_parser.api.AbstractTransaction; +import org.spacious_team.broker.report_parser.api.ReportTable; + +public class FinamReportTables extends AbstractReportTables { + + protected FinamReportTables(FinamBrokerReport report) { + super(report); + } + + @Override + public ReportTable getPortfolioPropertyTable() { + return new FinamPortfolioPropertyTable(report); + } + + @Override + public ReportTable getPortfolioCashTable() { + return emptyTable(); + } + + @Override + public ReportTable getCashFlowTable() { + return emptyTable(); + } + + @Override + public ReportTable getSecuritiesTable() { + return emptyTable(); + } + + @Override + public ReportTable getTransactionTable() { + return emptyTable(); + } + + @Override + public ReportTable getSecurityEventCashFlowTable() { + return emptyTable(); + } + + @Override + public ReportTable getSecurityQuoteTable() { + return emptyTable(); + } + + @Override + public ReportTable getForeignExchangeRateTable() { + return emptyTable(); + } +} diff --git a/src/main/java/ru/investbook/parser/finam/FinamReportTablesFactory.java b/src/main/java/ru/investbook/parser/finam/FinamReportTablesFactory.java new file mode 100644 index 00000000..2490aced --- /dev/null +++ b/src/main/java/ru/investbook/parser/finam/FinamReportTablesFactory.java @@ -0,0 +1,39 @@ +/* + * InvestBook + * Copyright (C) 2023 Spacious Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package ru.investbook.parser.finam; + +import org.spacious_team.broker.report_parser.api.BrokerReport; +import org.spacious_team.broker.report_parser.api.ReportTables; +import org.spacious_team.broker.report_parser.api.ReportTablesFactory; +import org.springframework.stereotype.Component; + +@Component +public class FinamReportTablesFactory implements ReportTablesFactory { + + + @Override + public boolean canCreate(BrokerReport brokerReport) { + return brokerReport instanceof FinamBrokerReport; + } + + @Override + public ReportTables create(BrokerReport brokerReport) { + return new FinamReportTables((FinamBrokerReport) brokerReport); + } +} From 16ce3097dcf6dfd0cbf6259a82f84818b6689c36 Mon Sep 17 00:00:00 2001 From: Vitalii Ananev Date: Thu, 26 Oct 2023 20:27:44 +0300 Subject: [PATCH 2/2] fix finam parser classes --- .../investbook/parser/finam/FinamBrokerReport.java | 12 ++++++------ .../parser/finam/FinamPortfolioPropertyTable.java | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/investbook/parser/finam/FinamBrokerReport.java b/src/main/java/ru/investbook/parser/finam/FinamBrokerReport.java index f5d5cd42..dbcba373 100644 --- a/src/main/java/ru/investbook/parser/finam/FinamBrokerReport.java +++ b/src/main/java/ru/investbook/parser/finam/FinamBrokerReport.java @@ -31,6 +31,8 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; +import static org.spacious_team.table_wrapper.api.TableCellAddress.NOT_FOUND; + @EqualsAndHashCode(callSuper = true) public class FinamBrokerReport extends AbstractExcelBrokerReport { @@ -57,10 +59,8 @@ private String getPortfolio(ReportPage reportPage) { try { return String.valueOf(reportPage.getNextColumnValue(PORTFOLIO_MARKER)); } catch (Exception e) { - // TODO: Дейсствительно ли тут влетает исключение? throw new IllegalArgumentException( - "В отчете не найден номер договора по заданному шаблону '" + PORTFOLIO_MARKER + "' XXX" - ); + "В отчете не найден номер договора по заданному шаблону '" + PORTFOLIO_MARKER + "' XXX"); } } @@ -75,19 +75,19 @@ private Instant getReportEndDateTime(ReportPage reportPage) { .plus(LAST_TRADE_HOUR, ChronoUnit.HOURS); } catch (Exception e) { throw new IllegalArgumentException( - "Не найдена дата отчета по заданному шаблону '" + REPORT_END_DATE_MARKER+ " XXX'" + "Не найдена дата отчета по заданному шаблону '" + REPORT_END_DATE_MARKER + " XXX'" ); } } public static void checkReportFormat(String excelFileName, ReportPage reportPage) { - if (reportPage.findByPrefix(UNIQ_TEXT, 2) == TableCellAddress.NOT_FOUND) { + if (reportPage.findByPrefix(UNIQ_TEXT, 2) == NOT_FOUND) { throw new RuntimeException("В файле " + excelFileName + " не содежится отчета брокера ФИНАМ"); } } @Override public void close() throws Exception { - this.book.close(); + book.close(); } } diff --git a/src/main/java/ru/investbook/parser/finam/FinamPortfolioPropertyTable.java b/src/main/java/ru/investbook/parser/finam/FinamPortfolioPropertyTable.java index bcb8293b..25412ca2 100644 --- a/src/main/java/ru/investbook/parser/finam/FinamPortfolioPropertyTable.java +++ b/src/main/java/ru/investbook/parser/finam/FinamPortfolioPropertyTable.java @@ -56,7 +56,7 @@ protected Table getSummaryTable() { return getSummaryTable(getReport(), ASSETS); } - public static Table getSummaryTable(BrokerReport report, String tableFooterString) { + private static Table getSummaryTable(BrokerReport report, String tableFooterString) { final Table table = report.getReportPage() .createNameless("На начало периода", tableFooterString, FinamSummaryTableHeader.class); if (table.isEmpty()) {