diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/hypothekarbanklenzburgag/HypothekarbankLenzburgAGPDFExtractorTest.java b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/hypothekarbanklenzburgag/HypothekarbankLenzburgAGPDFExtractorTest.java new file mode 100644 index 0000000000..dfadbca41f --- /dev/null +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/hypothekarbanklenzburgag/HypothekarbankLenzburgAGPDFExtractorTest.java @@ -0,0 +1,70 @@ +package name.abuchen.portfolio.datatransfer.pdf.hypothekarbanklenzburgag; + +import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasAmount; +import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasCurrencyCode; +import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasDate; +import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasFees; +import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasGrossValue; +import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasIsin; +import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasName; +import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasNote; +import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasShares; +import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasSource; +import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasTaxes; +import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasTicker; +import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.hasWkn; +import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.purchase; +import static name.abuchen.portfolio.datatransfer.ExtractorMatchers.security; +import static name.abuchen.portfolio.datatransfer.ExtractorTestUtilities.countAccountTransactions; +import static name.abuchen.portfolio.datatransfer.ExtractorTestUtilities.countBuySell; +import static name.abuchen.portfolio.datatransfer.ExtractorTestUtilities.countSecurities; +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.collection.IsEmptyCollection.empty; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import name.abuchen.portfolio.datatransfer.Extractor.Item; +import name.abuchen.portfolio.datatransfer.actions.AssertImportActions; +import name.abuchen.portfolio.datatransfer.pdf.HypothekarbankLenzburgAGPDFExtractor; +import name.abuchen.portfolio.datatransfer.pdf.PDFInputFile; +import name.abuchen.portfolio.model.Client; + +@SuppressWarnings("nls") +public class HypothekarbankLenzburgAGPDFExtractorTest +{ + @Test + public void testWertpapierKauf01() + { + HypothekarbankLenzburgAGPDFExtractor extractor = new HypothekarbankLenzburgAGPDFExtractor(new Client()); + + List errors = new ArrayList<>(); + + List results = extractor.extract(PDFInputFile.loadTestCase(getClass(), "Kauf01.txt"), errors); + + assertThat(errors, empty()); + assertThat(countSecurities(results), is(1L)); + assertThat(countBuySell(results), is(1L)); + assertThat(countAccountTransactions(results), is(0L)); + assertThat(results.size(), is(2)); + new AssertImportActions().check(results, "CHF"); + + // check security + assertThat(results, hasItem(security( // + hasIsin("IE000716YHJ7"), hasWkn("125615212"), hasTicker(null), // + hasName("Accum Shs USD Inve FTSE All"), // + hasCurrencyCode("CHF")))); + + // check buy sell transaction + assertThat(results, hasItem(purchase( // + hasDate("2024-03-14T00:00"), hasShares(720), // + hasSource("Kauf01.txt"), // + hasNote("Transaktion 61327806-0002"), // + hasAmount("CHF", 3974.14), hasGrossValue("CHF", 3948.48), // + hasTaxes("CHF", 5.92), hasFees("CHF", 19.74)))); + } +} diff --git a/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/hypothekarbanklenzburgag/Kauf01.txt b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/hypothekarbanklenzburgag/Kauf01.txt new file mode 100644 index 0000000000..3224a23800 --- /dev/null +++ b/name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/hypothekarbanklenzburgag/Kauf01.txt @@ -0,0 +1,31 @@ +PDFBox Version: 1.8.17 +Portfolio Performance Version: 0.68.2 +----------------------------------------- +Hypothekarbank Lenzburg AG +Bahnhofstrasse 2 | 5600 Lenzburg 1 +Telefon +41 62 885 11 11 | info@hbl.ch | www.hbl.ch +BC 8307 | HYPLCH22 | CHE-105.779.532 MWST +E-Post +Herr +Max Mustermann +Musterstrasse 1 +1234 Musterdorf +Ihr Betreuerteam: Service Center / Tel. +41 43 508 03 76 +Lenzburg, 14.03.2024 Seite 1 von 1 +Börse / Kauf Portfolio 314.391.703 +Transaktion 61327806-0002 +Wir haben am 14.03.2024 an der BX Swiss für Sie gekauft + 720 Accum Shs USD Inve FTSE All Depotstelle 3500 +Valor: 125615212 / IE000716YHJ7 +Menge 720 Kurs CHF 5.484 CHF 3'948.48 +Eidg. Umsatzabgabe CHF 5.92 +Eigene Kommission (NEON) CHF 19.74 +Belastung 314.391.304 Valuta 18.03.2024 CHF 3'974.14 +Neon Konto - neon +Die Titel buchen wir in Ihr Portfolio ein. +Dieser Auftrag erfolgte ohne Beratung durch die Bank. +Sofern für das gehandelte Finanzinstrument ein BIB vorhanden ist, wird Ihnen dieses auf unserer Internetseite unter +https://www.hbl.ch/de/private/anlegen/basisinformationsblatt/ zur Verfügung gestellt. +Freundliche Grüsse +Hypothekarbank Lenzburg AG +Anzeige ohne Unterschrift \ No newline at end of file diff --git a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/HypothekarbankLenzburgAGPDFExtractor.java b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/HypothekarbankLenzburgAGPDFExtractor.java new file mode 100644 index 0000000000..5fe8fa8f42 --- /dev/null +++ b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/HypothekarbankLenzburgAGPDFExtractor.java @@ -0,0 +1,152 @@ +package name.abuchen.portfolio.datatransfer.pdf; + +import static name.abuchen.portfolio.util.TextUtil.trim; + +import java.math.BigDecimal; + +import name.abuchen.portfolio.datatransfer.ExtractorUtils; +import name.abuchen.portfolio.datatransfer.pdf.PDFParser.Block; +import name.abuchen.portfolio.datatransfer.pdf.PDFParser.DocumentType; +import name.abuchen.portfolio.datatransfer.pdf.PDFParser.Transaction; +import name.abuchen.portfolio.model.BuySellEntry; +import name.abuchen.portfolio.model.Client; +import name.abuchen.portfolio.model.PortfolioTransaction; +import name.abuchen.portfolio.money.Values; + +/** + * @formatter:off + * @implNote Hypothekarbank Lenzburg AG + * + * @implSpec The Valorennumber number is the WKN number with 5 to 9 letters. + * @formatter:on + */ + +@SuppressWarnings("nls") +public class HypothekarbankLenzburgAGPDFExtractor extends AbstractPDFExtractor +{ + public HypothekarbankLenzburgAGPDFExtractor(Client client) + { + super(client); + + addBankIdentifier("Hypothekarbank Lenzburg AG"); + + addBuySellTransaction(); + } + + @Override + public String getLabel() + { + return "Hypothekarbank Lenzburg AG"; + } + + private void addBuySellTransaction() + { + DocumentType type = new DocumentType("Wir haben am .* f.r Sie gekauft"); + this.addDocumentTyp(type); + + Transaction pdfTransaction = new Transaction<>(); + + Block firstRelevantLine = new Block("^Transaktion .*$"); + type.addBlock(firstRelevantLine); + firstRelevantLine.set(pdfTransaction); + + pdfTransaction // + + .subject(() -> { + BuySellEntry portfolioTransaction = new BuySellEntry(); + portfolioTransaction.setType(PortfolioTransaction.Type.BUY); + return portfolioTransaction; + }) + + // @formatter:off + // Wir haben am 14.03.2024 an der BX Swiss für Sie gekauft + // 720 Accum Shs USD Inve FTSE All Depotstelle 3500 + // Valor: 125615212 / IE000716YHJ7 + // Menge 720 Kurs CHF 5.484 CHF 3'948.48 + // @formatter:on + .section("name", "wkn", "isin", "currency") // + .find("Wir haben am .* f.r Sie gekauft") //) + .match("^.*[\\,'\\d]+ (?.*) Depotstelle .*$") // + .match("^Valor: (?[A-Z0-9]{5,9}) \\/ (?[A-Z]{2}[A-Z0-9]{9}[0-9])$") + .match("^Menge[\\s]{1,}[\\.'\\d]+ Kurs (?[\\w]{3})[\\s]{1,}[\\.'\\d]+[\\s]{1,}[\\w]{3}[\\s]{1,}[\\.'\\d]+$") // + .assign((t, v) -> t.setSecurity(getOrCreateSecurity(v))) + + // @formatter:off + // Menge 720 Kurs CHF 5.484 CHF 3'948.48 + // @formatter:on + .section("shares") // + .match("^Menge[\\s]{1,}(?[\\.'\\d]+) Kurs.*$") // + .assign((t, v) -> t.setShares(asShares(v.get("shares")))) + + // @formatter:off + // Wir haben am 14.03.2024 an der BX Swiss für Sie gekauft + // @formatter:on + .section("date") // + .match("^Wir haben am (?[\\d]{2}\\.[\\d]{2}\\.[\\d]{4}).*$") // + .assign((t, v) -> t.setDate(asDate(v.get("date")))) + + // @formatter:off + // Belastung 314.391.304 Valuta 18.03.2024 CHF 3'974.14 + // @formatter:on + .section("currency", "amount") // + .match("^Belastung .* (?[\\w]{3})[\\s]{1,}(?[\\.'\\d]+)$") // + .assign((t, v) -> { + t.setCurrencyCode(asCurrencyCode(v.get("currency"))); + t.setAmount(asAmount(v.get("amount"))); + }) + + // @formatter:off + // Transaktion 61327806-0002 + // @formatter:on + .section("note").optional() // + .match("^(?Transaktion .*)$") // + .assign((t, v) -> t.setNote(trim(v.get("note")))) + + .wrap(BuySellEntryItem::new); + + addTaxesSectionsTransaction(pdfTransaction, type); + addFeesSectionsTransaction(pdfTransaction, type); + } + + private > void addTaxesSectionsTransaction(T transaction, DocumentType type) + { + transaction // + + // @formatter:off + // Eidg. Umsatzabgabe CHF 5.92 + // @formatter:on + .section("currency", "tax").optional() // + .match("^Eidg\\. Umsatzabgabe (?[\\w]{3})[\\s]{1,}(?[\\.'\\d]+)$") // + .assign((t, v) -> processTaxEntries(t, v, type)); + } + + private > void addFeesSectionsTransaction(T transaction, DocumentType type) + { + transaction // + + // @formatter:off + // Eigene Kommission (NEON) CHF 19.74 + // @formatter:on + .section("currency", "fee").optional() // + .match("^Eigene Kommission.* (?[\\w]{3})[\\s]{1,}(?[\\.'\\d]+)$") // + .assign((t, v) -> processFeeEntries(t, v, type)); + } + + @Override + protected long asAmount(String value) + { + return ExtractorUtils.convertToNumberLong(value, Values.Amount, "de", "CH"); + } + + @Override + protected long asShares(String value) + { + return ExtractorUtils.convertToNumberLong(value, Values.Share, "de", "CH"); + } + + @Override + protected BigDecimal asExchangeRate(String value) + { + return ExtractorUtils.convertToNumberBigDecimal(value, Values.Share, "de", "CH"); + } +} diff --git a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/PDFImportAssistant.java b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/PDFImportAssistant.java index 9b6becb6f6..828f8d844d 100644 --- a/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/PDFImportAssistant.java +++ b/name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/PDFImportAssistant.java @@ -67,6 +67,7 @@ public PDFImportAssistant(Client client, List files) extractors.add(new GladbacherBankAGPDFExtractor(client)); extractors.add(new HargreavesLansdownPlcExtractor(client)); extractors.add(new HelloBankPDFExtractor(client)); + extractors.add(new HypothekarbankLenzburgAGPDFExtractor(client)); extractors.add(new INGDiBaPDFExtractor(client)); extractors.add(new JTDirektbankPDFExtractor(client)); extractors.add(new KBCGroupNVPDFExtractor(client));