Skip to content

Commit

Permalink
Merge branch 'release/alpha0.9.0' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
MiguelTVMS committed Apr 10, 2023
2 parents 964abb2 + a88cf0b commit e159abe
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 121 deletions.
96 changes: 52 additions & 44 deletions .github/workflows/Main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,47 +46,55 @@ jobs:
- name: Run tests
run: dart test

# build:
# name: Build
# if: startsWith(github.ref, 'refs/tags/')
# needs: [test]
# strategy:
# matrix:
# #os: [ubuntu-latest, windows-latest, macos-latest]
# os: [ubuntu-latest]
# include:
# - os: ubuntu-latest
# target: linux-x64
# binary: brokertotax
# - os: windows-latest
# target: windows-x64
# binary: brokertotax.exe
# - os: macos-latest
# target: macos-x64

# runs-on: ${{ matrix.os }}

# steps:
# - uses: actions/checkout@v3

# - uses: dart-lang/setup-dart@v1

# - name: Cache dependencies
# uses: actions/cache@v3
# with:
# path: ~/.pub-cache
# key: ${{ runner.os }}-pub-${{ hashFiles('**/pubspec.lock') }}
# restore-keys: |
# ${{ runner.os }}-pub-

# - name: Install dependencies
# run: dart pub get

# - name: Build release
# run: dart compile exe bin/main.dart -o build/main

# - name: Upload release
# uses: actions/upload-artifact@v2
# with:
# name: main-${{ matrix.target }}
# path: build/main
build:
name: Build
if: startsWith(github.ref, 'refs/tags/')
needs: [test]
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
include:
- os: ubuntu-latest
target: linux-x64
binary: brokertotax
- os: windows-latest
target: windows-x64
binary: brokertotax.exe
- os: macos-latest
target: macos-x64

runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v3

- uses: dart-lang/setup-dart@v1

- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.pub-cache
key: ${{ runner.os }}-pub-${{ hashFiles('**/pubspec.lock') }}
restore-keys: |
${{ runner.os }}-pub-
- name: Generate build folder
run: mkdir build

- name: Copy data folder
run: cp -r data build/data

- name: Copy license
run: cp LICENSE build

- name: Install dependencies
run: dart pub get

- name: Build release
run: dart compile exe bin/main.dart -o build/${{ matrix.binary }}

- name: Upload release
uses: actions/upload-artifact@v2
with:
name: brokertotax-${{ matrix.target }}
path: build/**/*
2 changes: 1 addition & 1 deletion .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"exe",
"bin\\main.dart",
"-o",
"bin\\brokertotax.exe"
"build\\brokertotax.exe"
],
},
"args": [
Expand Down
9 changes: 7 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 1.0.0
## Alpha 0.9.0

- Initial version.
> **Note**
> This application is on a very early development phase.
- Able to interpret the eToro summary file.
- Able to group the transactions by type in Gains format.
- Generate a csv output file for each gain type.
11 changes: 0 additions & 11 deletions lib/entities/csv_property.dart

This file was deleted.

110 changes: 51 additions & 59 deletions lib/entities/gains.dart
Original file line number Diff line number Diff line change
@@ -1,66 +1,39 @@
import "dart:core";
import "dart:mirrors";

import "package:broker_to_tax/entities/exchange.dart";
import "package:broker_to_tax/entities/transaction_type.dart";
import "package:country_code/country_code.dart";
import "package:csv/csv.dart";
import "package:logging/logging.dart";
import "csv_property.dart";

class Gain {
@CsvProperty("Name")
String name;

@CsvProperty("Open Date")
DateTime openDate;

@CsvProperty("Close Date")
DateTime closeDate;

@CsvProperty("Units")
double units;

@CsvProperty("Open Rate")
double openRate;

@CsvProperty("Close Rate")
double closeRate;

@CsvProperty("Fees & Dividends")
double feesAndDividends;

@CsvProperty("Type")
TransactionType type;

@CsvProperty("Source Country")
CountryCode sourceCountry;

@CsvProperty("Counterparty Country")
CountryCode counterpartyCountry;

double? _openValue;
@CsvProperty("Open Value")
double get openValue => _openValue ??= units * openRate;

double? _closeValue;
@CsvProperty("Close Value")
double get closeValue => _closeValue ??= units * closeRate;

double? _grossProfit;
@CsvProperty("Gross Profit")
double get grossProfit => _grossProfit ??= closeValue - openValue;

double? _netProfit;
@CsvProperty("Net Profit")
double get netProfit => _netProfit ??= closeValue - openValue + feesAndDividends;

ExchangeRate? _openExchangeRate;
//@GainCsvProperty("Open Exchange Rate")
ExchangeRate get openExchangeRate => _openExchangeRate ??= HistoricalExchangeRates()[openDate]!;

ExchangeRate? _closeExchangeRate;
//@GainCsvProperty("Close Exchange Rate")
ExchangeRate get closeExchangeRate => _closeExchangeRate ??= HistoricalExchangeRates()[openDate]!;

Gain(
Expand All @@ -75,19 +48,14 @@ class Gain {
required this.sourceCountry,
required this.counterpartyCountry});

@CsvProperty("Converted Open Value", currencyParameterIndex: 0)
double getOpenValueIn(Currency symbol) => openExchangeRate.convert(openValue, symbol);

@CsvProperty("Converted Close Value", currencyParameterIndex: 0)
double getCloseValueIn(Currency symbol) => closeExchangeRate.convert(closeValue, symbol);

@CsvProperty("Converted Fees and Dividends", currencyParameterIndex: 0)
double getFeesAndDividendsIn(Currency symbol) => closeExchangeRate.convert(feesAndDividends, symbol);

@CsvProperty("Converted Gross Profit", currencyParameterIndex: 0)
double getGrossProfitIn(Currency symbol) => getCloseValueIn(symbol) - getOpenValueIn(symbol);

@CsvProperty("Converted Net Profit", currencyParameterIndex: 0)
double getNetProfitIn(Currency symbol) =>
getCloseValueIn(symbol) - getOpenValueIn(symbol) + getFeesAndDividendsIn(symbol);
}
Expand Down Expand Up @@ -147,38 +115,62 @@ extension GainsExtension on Iterable<Gain> {
_log.fine("Generating CSV for $length gains in $currency");

List<List<dynamic>> csvRows = <List<dynamic>>[];
Map<String, CsvProperty> columns = <String, CsvProperty>{};

var classMirror = reflectClass(Gain);
for (var v in classMirror.declarations.values
.where((e) => e.metadata.where((m) => m.reflectee is CsvProperty).isNotEmpty)) {
_log.finer("Found GainCsvProperty metadata in ${v.simpleName}");
var name = MirrorSystem.getName(v.simpleName);
columns[name] = v.metadata.where((meta) => meta.reflectee is CsvProperty).first.reflectee as CsvProperty;
_log.finest("Added column $name named ${columns[name]}");
}
List<String> headerColumns = <String>[
"name",
"Open Date",
"Close Date",
"Units",
"OpenRate",
"CloseRate",
"Fees and Dividends",
"Type",
"Source Country",
"Counterparty Country",
"Open Value",
"Close Value",
"Gross Profit",
"Net Profit",
"Open $currency ExchangeRate",
"Close $currency ExchangeRate",
"Open Value in $currency",
"Close Value in $currency",
"Fees and Dividends in $currency",
"Gross Profit in $currency",
"Net Profit in $currency"
];

if (addHeader) {
_log.fine("Adding header");
csvRows.add(columns.values.map((e) => e.name).toList());
csvRows.add(headerColumns);
}

forEach((gain) {
var gainMirror = reflect(gain);
var csvCols = <dynamic>[];
columns.forEach((key, value) {
if (value.isMethod) {
//TODO: Support more than one parameter
var params = <dynamic>[currency];
var methodMirror = gainMirror.invoke(Symbol(key), params);
csvCols.add(methodMirror.reflectee);
} else {
var variableMirror = gainMirror.getField(Symbol(key));
csvCols.add(variableMirror.reflectee);
}
});
csvRows.add(csvCols);
});
for (Gain gain in this) {
List<dynamic> csvColumns = <dynamic>[
gain.name,
gain.openDate,
gain.closeDate,
gain.units.toStringAsFixed(2),
gain.openRate.toStringAsFixed(2),
gain.closeRate.toStringAsFixed(2),
gain.feesAndDividends.toStringAsFixed(2),
gain.type,
gain.sourceCountry.alpha2,
gain.counterpartyCountry.alpha2,
gain.openValue.toStringAsFixed(2),
gain.closeValue.toStringAsFixed(2),
gain.grossProfit.toStringAsFixed(2),
gain.netProfit.toStringAsFixed(2),
gain.openExchangeRate[currency],
gain.closeExchangeRate[currency],
gain.getOpenValueIn(currency).toStringAsFixed(2),
gain.getCloseValueIn(currency).toStringAsFixed(2),
gain.getFeesAndDividendsIn(currency).toStringAsFixed(2),
gain.getGrossProfitIn(currency).toStringAsFixed(2),
gain.getNetProfitIn(currency).toStringAsFixed(2)
];

csvRows.add(csvColumns);
}

return ListToCsvConverter().convert(csvRows);
}
Expand Down
9 changes: 5 additions & 4 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
name: broker_to_tax
description: A sample command-line application.
version: 1.0.0
# repository: https://github.com/my_org/my_repo
description: A simple cli application that transforms information from brokers to the Portuguese tax information.
version: 0.9.0
repository: https://github.com/MiguelTVMS/broker_to_tax
issue_tracker: https://github.com/MiguelTVMS/broker_to_tax/issues

environment:
sdk: '>=2.19.5 <3.0.0'
sdk: ">=2.19.5 <3.0.0"

# dependencies:
# path: ^1.8.0
Expand Down
13 changes: 13 additions & 0 deletions test/etoro_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,19 @@ void main() {

expect(positionCloseValue, gainsCloseValue);
});
test("Date parse is correct", () {
var positions = EtoroClosedPositions.fromCsv(csvString);
var position = positions.firstWhere((element) => element.positionId == 2316622589);

// 04/11/2022 13:31:25
var expectedOpenDate = DateTime(2022, 11, 4, 13, 31, 25);

// 21/12/2022 15:49:30
var expectedCloseDate = DateTime(2022, 12, 21, 15, 49, 30);

expect(position.openDate, expectedOpenDate);
expect(position.closeDate, expectedCloseDate);
});
test("Has Stock position", () {
var positions = EtoroClosedPositions.fromCsv(csvString);
var gains = positions.toGains();
Expand Down

0 comments on commit e159abe

Please sign in to comment.