Skip to content

Commit

Permalink
Added support for parsing of dividends from Revolut.
Browse files Browse the repository at this point in the history
  • Loading branch information
Vladimír Aubrecht authored and Vladimír Aubrecht committed Mar 6, 2020
1 parent a8034f7 commit 437119b
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 3 deletions.
4 changes: 2 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/StatementParser/TaxReporterCLI/bin/Debug/netcoreapp3.0/TaxReporterCLI.dll",
//"args": ["-x", "/Users/vladimiraubrecht/Documents/Taxes/2019/Report2019.xlsx", "/Users/vladimiraubrecht/Documents/Taxes/2019/Statements"],
//"args": ["/Users/vladimiraubrecht/Downloads/03-31-stat.pdf"],
"args": ["-x", "/Users/vladimiraubrecht/Documents/Taxes/2019/test.xlsx", "/Users/vladimiraubrecht/Documents/Taxes/2019/Statements/"],
"args": ["/Users/vladimiraubrecht/Library/Mobile Documents/com~apple~CloudDocs/Downloads/d6fe7c6b-56a2-41e1-9118-b079e607ace7.pdf"],
//"args": ["-x", "/Users/vladimiraubrecht/Documents/Taxes/2019/test.xlsx", "/Users/vladimiraubrecht/Documents/Taxes/2019/Statements/"],
"cwd": "${workspaceFolder}/StatementParser/TaxReporterCLI",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "internalConsole",
Expand Down
2 changes: 1 addition & 1 deletion StatementParser/StatementParser/Models/Broker.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace StatementParser.Models
{
public enum Broker { MorganStanley, Fidelity, FxChoice, Degiro, Lynx }
public enum Broker { MorganStanley, Fidelity, FxChoice, Degiro, Lynx, Revolut }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using ASoft.TextDeserializer.Attributes;

namespace StatementParser.Parsers.Brokers.Revolut.PdfModels
{
[DeserializeByRegex("(?<TradeDate>[0-9]{2}/[0-9]{2}/[0-9]{4})(?<SettleDate>[0-9]{2}/[0-9]{2}/[0-9]{4})(?<Currency>[A-Z]{3})(?<ActivityType>DIVNRA|DIV)(?<Description>.+?)00.00(?<AmountRaw>\\(?\\d+\\.\\d{2}\\)?)")]
internal class ActivityDividendModel
{
public DateTime TradeDate { get; set; }

public DateTime SettleDate { get; set; }

public string Currency { get; set; }

public string ActivityType { get; set; }

public string Description { get; set; }

public decimal Amount => decimal.Parse(AmountRaw.Replace('(', '-').TrimEnd(')'));
public string AmountRaw { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using ASoft.TextDeserializer.Attributes;

namespace StatementParser.Parsers.Brokers.Revolut.PdfModels
{
[DeserializeByRegex(" (?<AccountNumber>[^ ]+)Account")]
internal class StatementModel
{
public string AccountNumber { get; set; }

[DeserializeCollectionByRegex(
"([0-9]{2}/[0-9]{2}/[0-9]{4}[0-9]{2}/[0-9]{2}/[0-9]{4})",
"HOLDINGSACTIVITYTrade DateSettle DateCurrencyActivity TypeSymbol / DescriptionQuantityPriceAmount(.+)Page \\d+ of \\d+")]
public ActivityDividendModel[] ActivityDividend { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ASoft.TextDeserializer;
using ASoft.TextDeserializer.Exceptions;
using StatementParser.Models;
using StatementParser.Parsers.Brokers.Revolut.PdfModels;

namespace StatementParser.Parsers.Brokers.Revolut
{
internal class RevolutStatementParser : ITransactionParser
{
private bool CanParse(string statementFilePath)
{
return File.Exists(statementFilePath) && Path.GetExtension(statementFilePath).ToLowerInvariant() == ".pdf";
}

public IList<Transaction> Parse(string statementFilePath)
{
if (!CanParse(statementFilePath))
{
return null;
}

var transactions = new List<Transaction>();

using (var textSource = new TextSource(statementFilePath))
{
try
{
var parsedDocument = new TextDocumentParser<StatementModel>().Parse(textSource);

foreach (var transaction in parsedDocument.ActivityDividend)
{
if (transaction.ActivityType == "DIV")
{
transactions.Add(CreateDividendTransaction(transaction, parsedDocument.ActivityDividend));
}
}

}
catch (TextException)
{
return null;
}
}

return transactions;
}

private DividendTransaction CreateDividendTransaction(ActivityDividendModel activityDividendRow, ActivityDividendModel[] activities)
{
decimal tax = SearchForTax(activityDividendRow, activities);
var currency = (Currency)Enum.Parse(typeof(Currency), activityDividendRow.Currency);
return new DividendTransaction(Broker.Revolut, activityDividendRow.SettleDate, activityDividendRow.Description, activityDividendRow.Amount, tax, currency);
}

private decimal SearchForTax(ActivityDividendModel dividendTransactionRow, ActivityDividendModel[] activities)
{
var transactionRow = activities.FirstOrDefault(i =>
i.ActivityType == "DIVNRA" &&
i.TradeDate == dividendTransactionRow.TradeDate &&
i.SettleDate == dividendTransactionRow.SettleDate &&
i.Description.Substring(0, i.Description.IndexOf(" - DIV")) == dividendTransactionRow.Description.Substring(0, dividendTransactionRow.Description.IndexOf(" - DIV"))
);

return transactionRow?.Amount ?? 0;
}
}
}
2 changes: 2 additions & 0 deletions StatementParser/StatementParser/TransactionParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using StatementParser.Parsers.Brokers.FxChoice;
using StatementParser.Parsers.Brokers.Lynx;
using StatementParser.Parsers.Brokers.MorganStanley;
using StatementParser.Parsers.Brokers.Revolut;

namespace StatementParser
{
Expand All @@ -22,6 +23,7 @@ public TransactionParser()
parsers.Add(new FxChoiceStatementParser());
parsers.Add(new LynxCsvParser());
parsers.Add(new DegiroParser());
parsers.Add(new RevolutStatementParser());
}

public Task<IList<Transaction>> ParseAsync(string statementFilePath)
Expand Down

0 comments on commit 437119b

Please sign in to comment.