Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Trade Republic PDF import when selling with tax refund #1666

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ public void testVerkauf02()
List<Item> results = extractor.extract(PDFInputFile.loadTestCase(getClass(), "Verkauf02.txt"), errors);

assertThat(errors, empty());
assertThat(results.size(), is(4));
assertThat(results.size(), is(3));
new AssertImportActions().check(results, CurrencyUnit.EUR);

// check security
Expand All @@ -283,7 +283,7 @@ public void testVerkauf02()
assertThat(tx.getType(), is(PortfolioTransaction.Type.SELL));
assertThat(entry.getAccountTransaction().getType(), is(AccountTransaction.Type.SELL));

assertThat(tx.getMonetaryAmount(), is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(3615.63))));
assertThat(tx.getMonetaryAmount(), is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(3594.00))));
assertThat(tx.getDateTime(), is(LocalDateTime.parse("2020-06-10T11:42")));
assertThat(tx.getShares(), is(Values.Share.factorize(500)));
assertThat(tx.getUnitSum(Unit.Type.FEE), is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(1))));
Expand All @@ -298,9 +298,45 @@ public void testVerkauf02()
// assert transaction
assertThat(transaction.getType(), is(AccountTransaction.Type.TAX_REFUND));
assertThat(transaction.getDateTime(), is(LocalDateTime.parse("2020-06-12T00:00")));
assertThat(transaction.getAmount(), is(Values.Amount.factorize(20.5)));
assertThat(transaction.getAmount(), is(Values.Amount.factorize(21.63)));
assertThat(transaction.getCurrencyCode(), is(CurrencyUnit.EUR));
}
}

@Test
public void testVerkauf03()
{
TradeRepublicPDFExtractor extractor = new TradeRepublicPDFExtractor(new Client());

List<Exception> errors = new ArrayList<>();

List<Item> results = extractor.extract(PDFInputFile.loadTestCase(getClass(), "Verkauf03.txt"), errors);

assertThat(errors, empty());
assertThat(results.size(), is(3));
new AssertImportActions().check(results, CurrencyUnit.EUR);

// check security
Optional<Item> item = results.stream().filter(i -> i instanceof SecurityItem).findFirst();
Security security = ((SecurityItem) item.orElseThrow(IllegalArgumentException::new)).getSecurity();
assertThat(security.getIsin(), is("DE0007100000"));
assertThat(security.getName(), is("Daimler AG"));
assertThat(security.getCurrencyCode(), is(CurrencyUnit.EUR));

// check transaction
item = results.stream().filter(i -> i instanceof BuySellEntryItem).findFirst();
BuySellEntry entry = (BuySellEntry) item.orElseThrow(IllegalArgumentException::new).getSubject();
PortfolioTransaction tx = entry.getPortfolioTransaction();

assertThat(tx.getType(), is(PortfolioTransaction.Type.SELL));
assertThat(entry.getAccountTransaction().getType(), is(AccountTransaction.Type.SELL));

assertThat(tx.getMonetaryAmount(), is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(1199.00))));
assertThat(tx.getDateTime(), is(LocalDateTime.parse("2020-07-21T09:30")));
assertThat(tx.getShares(), is(Values.Share.factorize(30)));
assertThat(tx.getUnitSum(Unit.Type.FEE), is(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(1))));

Iterator<Extractor.Item> iter = results.stream().filter(i -> i instanceof TransactionItem).iterator();
if (iter.hasNext())
{
Item i = iter.next();
Expand All @@ -309,8 +345,8 @@ public void testVerkauf02()

// assert transaction
assertThat(transaction.getType(), is(AccountTransaction.Type.TAX_REFUND));
assertThat(transaction.getDateTime(), is(LocalDateTime.parse("2020-06-12T00:00")));
assertThat(transaction.getAmount(), is(Values.Amount.factorize(1.13)));
assertThat(transaction.getDateTime(), is(LocalDateTime.parse("2020-07-23T00:00")));
assertThat(transaction.getAmount(), is(Values.Amount.factorize(139.58)));
assertThat(transaction.getCurrencyCode(), is(CurrencyUnit.EUR));
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
PDF Autor: ''
PDFBox Version: 1.8.16
-----------------------------------------
TRADE REPUBLIC BANK GMBH KASTANIENALLEE 32 10435 BERLIN
xxxxxx xxxx SEITE 1 von 1
xxxx 1 DATUM 21.07.2020
D xxxxxx xxxxx ORDER c17d-baea
AUSFÜHRUNG 6415-fd77
DEPOT 1xxxxxxxxx
WERTPAPIERABRECHNUNG
ÜBERSICHT
Limit-Order Verkauf am 21.07.2020, um 09:30 Uhr an der Lang & Schwarz Exchange.
Der Kontrahent der Transaktion ist Lang & Schwarz TradeCenter AG & Co. KG.
POSITION ANZAHL KURS BETRAG
Daimler AG 30 Stk. 40,00 EUR 1.200,00 EUR
Namens-Aktien o.N.
ISIN: DE0007100000
GESAMT 1.200,00 EUR
ABRECHNUNG
POSITION BETRAG
Fremdkostenzuschlag -1,00 EUR
Kapitalertragssteuer Optimierung 122,98 EUR
Solidaritätszuschlag Optimierung 6,76 EUR
Kirchensteuer Optimierung 9,84 EUR
GESAMT 1.338,58 EUR
BUCHUNG
VERRECHNUNGSKONTO VALUTA BETRAG
DExxxxxxxxxxxxx 23.07.2020 1.338,58 EUR
Daimler AG Namens-Aktien o.N. in Girosammelverwahrung.
Diese Abrechnung wird maschinell erstellt und daher nicht unterschrieben.
Sofern keine Umsatzsteuer ausgewiesen ist, handelt es sich gem. § 4 Nr. 8 UStG um eine umsatzsteuerfreie
Leistung.
Trade Republic Bank GmbH www.traderepublic.com Sitz der Gesellschaft: Düsseldorf Geschäftsführer
Kastanienallee 32 service@traderepublic.com AG Düsseldorf HRB 85864 Andreas Willius
10435 Berlin USt-ID DE307510626 Karsten Müller
ABRE / 2020-07-21 / 32838682 / 4b17-d56a
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@ private void addSellTransaction()
.addUnit(new Unit(Unit.Type.TAX,
Money.of(asCurrencyCode(v.get("currency")),
asAmount(v.get("tax"))))))
// check for negative tax (optimization)
.section("tax", "currency").optional() //
.match("Kapitalertragssteuer Optimierung (?<tax>[\\d+,.]*) (?<currency>\\w{3}+)")
.assign((t, v) -> {
t.setAmount(t.getPortfolioTransaction().getAmount() - asAmount(v.get("tax")));
})

.section("tax", "currency") //
.optional() //
Expand All @@ -137,64 +143,57 @@ private void addSellTransaction()
Money.of(asCurrencyCode(v.get("currency")),
asAmount(v.get("tax"))))))

// check for negative tax (optimization)
.section("tax", "currency").optional() //
.match("Solidaritätszuschlag Optimierung (?<tax>[\\d+,.]*) (?<currency>\\w{3}+)")
.assign((t, v) -> {
t.setAmount(t.getPortfolioTransaction().getAmount() - asAmount(v.get("tax")));
})

// check for negative tax (optimization)
.section("tax", "currency").optional() //
.match("Kirchensteuer Optimierung (?<tax>[\\d+,.]*) (?<currency>\\w{3}+)")
.assign((t, v) -> {
t.setAmount(t.getPortfolioTransaction().getAmount() - asAmount(v.get("tax")));
})

.wrap(BuySellEntryItem::new));

Block witholdingTaxBlock = new Block("Kapitalertragssteuer Optimierung.*");
type.addBlock(witholdingTaxBlock);
witholdingTaxBlock.set(new Transaction<AccountTransaction>().subject(() -> {
Block taxBlock = new Block("Kapitalertragssteuer Optimierung.*");
type.addBlock(taxBlock);
taxBlock.set(new Transaction<AccountTransaction>().subject(() -> {
AccountTransaction t = new AccountTransaction();
t.setType(AccountTransaction.Type.TAX_REFUND);
return t;
})

// check for negative tax (optimization)
.section("tax", "currency", "date") //
.optional() //
.match("Kapitalertragssteuer Optimierung (?<tax>[\\d+,.]*) (\\w{3}+)")
.section("tax", "currency", "date").optional() //
.match("Kapitalertragssteuer Optimierung (?<tax>[\\d+,.]*) (?<currency>\\w{3}+)")
.match("VERRECHNUNGSKONTO VALUTA BETRAG")
.match(".* (?<date>\\d+.\\d+.\\d{4}+) (?<amount>[\\d+,.]*) (?<currency>\\w{3}+)")
.match(".* (?<date>\\d+.\\d+.\\d{4}+) (?<amount>[\\d+,.]*) (\\w{3}+)")
.assign((t, v) -> {
t.setAmount(asAmount(v.get("tax")));
t.setCurrencyCode(asCurrencyCode(v.get("currency")));
t.setDateTime(asDate(v.get("date")));
}).wrap(t -> new TransactionItem(t)));

Block solidarityTaxBlock = new Block("Solidaritätszuschlag Optimierung.*");
type.addBlock(solidarityTaxBlock);
solidarityTaxBlock.set(new Transaction<AccountTransaction>().subject(() -> {
AccountTransaction t = new AccountTransaction();
t.setType(AccountTransaction.Type.TAX_REFUND);
return t;
})
})

// check for negative tax (optimization)
.section("tax", "currency", "date") //
.optional() //
.match("Solidaritätszuschlag Optimierung (?<tax>[\\d+,.]*) (\\w{3}+)")
.section("tax", "currency", "date").optional() //
.match("Solidaritätszuschlag Optimierung (?<tax>[\\d+,.]*) (?<currency>\\w{3}+)")
.match("VERRECHNUNGSKONTO VALUTA BETRAG")
.match(".* (?<date>\\d+.\\d+.\\d{4}+) (?<amount>[\\d+,.]*) (?<currency>\\w{3}+)")
.match(".* (?<date>\\d+.\\d+.\\d{4}+) (?<amount>[\\d+,.]*) (\\w{3}+)")
.assign((t, v) -> {
t.setAmount(asAmount(v.get("tax")));
t.setAmount(t.getAmount() + asAmount(v.get("tax")));
t.setCurrencyCode(asCurrencyCode(v.get("currency")));
t.setDateTime(asDate(v.get("date")));
}).wrap(t -> new TransactionItem(t)));

Block churchTaxBlock = new Block("Kirchensteuer Optimierung.*");
type.addBlock(churchTaxBlock);
churchTaxBlock.set(new Transaction<AccountTransaction>().subject(() -> {
AccountTransaction t = new AccountTransaction();
t.setType(AccountTransaction.Type.TAX_REFUND);
return t;
})
})

// check for negative tax (optimization)
.section("tax", "currency", "date") //
.optional() //
.match("Kirchensteuer Optimierung (?<tax>[\\d+,.]*) (\\w{3}+)")
.section("tax", "currency", "date").optional() //
.match("Kirchensteuer Optimierung (?<tax>[\\d+,.]*) (?<currency>\\w{3}+)")
.match("VERRECHNUNGSKONTO VALUTA BETRAG")
.match(".* (?<date>\\d+.\\d+.\\d{4}+) (?<amount>[\\d+,.]*) (?<currency>\\w{3}+)")
.match(".* (?<date>\\d+.\\d+.\\d{4}+) (?<amount>[\\d+,.]*) (\\w{3}+)")
.assign((t, v) -> {
t.setAmount(asAmount(v.get("tax")));
t.setAmount(t.getAmount() + asAmount(v.get("tax")));
t.setCurrencyCode(asCurrencyCode(v.get("currency")));
t.setDateTime(asDate(v.get("date")));
}).wrap(t -> new TransactionItem(t)));
Expand Down