This commit is contained in:
2025-03-18 15:04:41 +01:00
parent fc1ef6f3ec
commit aa52f216bd
14 changed files with 107 additions and 53 deletions
+8 -8
View File
@@ -4,9 +4,14 @@
"minimum-stability": "stable", "minimum-stability": "stable",
"prefer-stable": true, "prefer-stable": true,
"require": { "require": {
"php": ">=7.4", "php": ">=8.1",
"ext-ctype": "*", "ext-ctype": "*",
"ext-curl": "*",
"ext-dom": "*",
"ext-iconv": "*", "ext-iconv": "*",
"ext-json": "*",
"ext-libxml": "*",
"ext-simplexml": "*",
"doctrine/annotations": "^1.0", "doctrine/annotations": "^1.0",
"doctrine/doctrine-bundle": "^2.5", "doctrine/doctrine-bundle": "^2.5",
"doctrine/doctrine-migrations-bundle": "^3.2", "doctrine/doctrine-migrations-bundle": "^3.2",
@@ -20,7 +25,7 @@
"symfony/doctrine-messenger": "5.4.*", "symfony/doctrine-messenger": "5.4.*",
"symfony/dotenv": "5.4.*", "symfony/dotenv": "5.4.*",
"symfony/expression-language": "5.4.*", "symfony/expression-language": "5.4.*",
"symfony/flex": "^1.17|^2", "symfony/flex": "^1.21",
"symfony/form": "5.4.*", "symfony/form": "5.4.*",
"symfony/framework-bundle": "5.4.*", "symfony/framework-bundle": "5.4.*",
"symfony/http-client": "5.4.*", "symfony/http-client": "5.4.*",
@@ -45,12 +50,7 @@
"symfony/webpack-encore-bundle": "^1.14", "symfony/webpack-encore-bundle": "^1.14",
"symfony/yaml": "5.4.*", "symfony/yaml": "5.4.*",
"twig/extra-bundle": "^2.12|^3.0", "twig/extra-bundle": "^2.12|^3.0",
"twig/twig": "^2.12|^3.0", "twig/twig": "^2.12|^3.0"
"ext-curl": "*",
"ext-json": "*",
"ext-simplexml": "*",
"ext-dom": "*",
"ext-libxml": "*"
}, },
"config": { "config": {
"allow-plugins": { "allow-plugins": {
+15 -10
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "c7d5407f0c4f5f2541c1ca93c55b048e", "content-hash": "7f8576ede293dfe8fab8567bc5745665",
"packages": [ "packages": [
{ {
"name": "doctrine/annotations", "name": "doctrine/annotations",
@@ -4159,16 +4159,16 @@
}, },
{ {
"name": "symfony/flex", "name": "symfony/flex",
"version": "v1.18.5", "version": "v1.21.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/flex.git", "url": "https://github.com/symfony/flex.git",
"reference": "10e438f53a972439675dc720706f0cd5c0ed94f1" "reference": "06b58a5e5b4c6528fb12e0fac5fea0db3f1e7ae8"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/flex/zipball/10e438f53a972439675dc720706f0cd5c0ed94f1", "url": "https://api.github.com/repos/symfony/flex/zipball/06b58a5e5b4c6528fb12e0fac5fea0db3f1e7ae8",
"reference": "10e438f53a972439675dc720706f0cd5c0ed94f1", "reference": "06b58a5e5b4c6528fb12e0fac5fea0db3f1e7ae8",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -4204,7 +4204,7 @@
"description": "Composer plugin for Symfony", "description": "Composer plugin for Symfony",
"support": { "support": {
"issues": "https://github.com/symfony/flex/issues", "issues": "https://github.com/symfony/flex/issues",
"source": "https://github.com/symfony/flex/tree/v1.18.5" "source": "https://github.com/symfony/flex/tree/v1.21.6"
}, },
"funding": [ "funding": [
{ {
@@ -4220,7 +4220,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-02-16T17:26:46+00:00" "time": "2024-03-02T08:16:37+00:00"
}, },
{ {
"name": "symfony/form", "name": "symfony/form",
@@ -8976,10 +8976,15 @@
"prefer-stable": true, "prefer-stable": true,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {
"php": ">=7.2.5", "php": ">=7.4",
"ext-ctype": "*", "ext-ctype": "*",
"ext-iconv": "*" "ext-curl": "*",
"ext-dom": "*",
"ext-iconv": "*",
"ext-json": "*",
"ext-libxml": "*",
"ext-simplexml": "*"
}, },
"platform-dev": [], "platform-dev": [],
"plugin-api-version": "2.2.0" "plugin-api-version": "2.3.0"
} }
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace App\Enum;
enum MarketNames: int
{
case IBKR = 1;
case MBANK = 2;
case EXANTE = 3;
public static function tryFromCase(string $value): ?MarketNames
{
$ret = null;
foreach (self::cases() as $case) {
if (str_contains($value, strtolower($case->name))) {
$ret = $case;
break;
}
}
return $ret;
}
}
+1 -2
View File
@@ -7,7 +7,7 @@ use Doctrine\ORM\EntityManager;
class Currency class Currency
{ {
public static array $currencies = ["USD","GBP","PLN","EUR","CAD"]; public static array $currencies = ["USD","GBP","PLN","EUR","CAD","AUD"];
public static array $currenciesCrypto = ["USDT"]; public static array $currenciesCrypto = ["USDT"];
private static string $apiUrl = "https://api.nbp.pl/api/exchangerates/rates/a/:code/:date/?format=json"; private static string $apiUrl = "https://api.nbp.pl/api/exchangerates/rates/a/:code/:date/?format=json";
private EntityManager $manager; private EntityManager $manager;
@@ -30,7 +30,6 @@ class Currency
} }
$dateTime->modify("-$minusDay days"); $dateTime->modify("-$minusDay days");
$dateStr = $dateTime->format("Ymd"); $dateStr = $dateTime->format("Ymd");
if (isset($this->ratesPerDate[$currency]) && isset($this->ratesPerDate[$currency][$dateStr])) { if (isset($this->ratesPerDate[$currency]) && isset($this->ratesPerDate[$currency][$dateStr])) {
return $this->ratesPerDate[$currency][$dateStr]; return $this->ratesPerDate[$currency][$dateStr];
} }
@@ -20,6 +20,7 @@ class DividendValues
public static function searchForKeyName(string $val) : ?string public static function searchForKeyName(string $val) : ?string
{ {
$ret=null; $ret=null;
$val = trim($val);
foreach (self::$samples as $key => $sample) { foreach (self::$samples as $key => $sample) {
foreach ($sample as $item) { foreach ($sample as $item) {
if (strpos($val, $item) !== false) { if (strpos($val, $item) !== false) {
+7 -2
View File
@@ -2,17 +2,20 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Helper\Sheets; namespace App\Helper\Sheets;
use App\Enum\MarketNames;
use PhpOffice\PhpSpreadsheet\IOFactory; use PhpOffice\PhpSpreadsheet\IOFactory;
class ReadSheet class ReadSheet
{ {
private string $filePath; private string $filePath;
private array $arr=[]; private array $arr=[];
private ?MarketNames $marketNames;
public function __construct(string $file) public function __construct(string $file, ?MarketNames $marketNames)
{ {
if (file_exists($file)){ if (file_exists($file)){
$this->filePath = $file; $this->filePath = $file;
$this->marketNames = $marketNames;
} }
} }
@@ -27,10 +30,12 @@ class ReadSheet
return false; return false;
} }
$fileType = explode(".", $this->filePath)[1]; $fileType = explode(".", $this->filePath)[1];
$reader = IOFactory::createReader(ucfirst($fileType)); $reader = IOFactory::createReader(ucfirst($fileType));
$reader->setLoadAllSheets(); $reader->setLoadAllSheets();
$reader->setReadDataOnly(true); $reader->setReadDataOnly(true);
if ($this->marketNames && $this->marketNames === MarketNames::EXANTE) {
$reader->setInputEncoding("UTF-16");
}
if ($delimiter) { if ($delimiter) {
$reader->setDelimiter($delimiter); $reader->setDelimiter($delimiter);
} }
@@ -104,6 +104,6 @@ final class DividendsData
*/ */
public function setCurrency(string $currency): void public function setCurrency(string $currency): void
{ {
$this->currency = $currency; $this->currency = trim($currency);
} }
} }
@@ -81,13 +81,15 @@ class DividendsSummary
if (!isset($test[$country]['incomes'][$val->getTax()])) { if (!isset($test[$country]['incomes'][$val->getTax()])) {
$test[$country]['incomes'][$val->getTax()] = 0; $test[$country]['incomes'][$val->getTax()] = 0;
} }
if ($this->getRate($val) < 1) {
die("Rate for date: ".$val->getDateTime()->format("Y-m-d")." / ".$val->getCurrency() . " is 0");
}
$income = round($val->getCount()*$val->getValue()*$this->getRate($val),5); $income = round($val->getCount()*$val->getValue()*$this->getRate($val),5);
$test[$country]['incomeAll'] += $income; $test[$country]['incomeAll'] += $income;
$test[$country]['tax'] += round($this->count($val),5); $test[$country]['tax'] += round($this->count($val),5);
$test[$country]['destiny_tax'] += round($this->count($val,true),5); $test[$country]['destiny_tax'] += round($this->count($val,true),5);
$test[$country]['tax_cost'] += round($this->countTaxPrice($val),5); $test[$country]['tax_cost'] += round($this->countTaxPrice($val),5);
$test[$country]['incomes'][$val->getTax()] += $income; $test[$country]['incomes'][$val->getTax()] += $income;
if (!isset($countryToCurrency[$country])) { if (!isset($countryToCurrency[$country])) {
$countryToCurrency[$country] = $val->getCurrency(); $countryToCurrency[$country] = $val->getCurrency();
} }
+9 -7
View File
@@ -14,10 +14,11 @@ class ExanteSheet extends SheetDataAll
continue; continue;
} }
foreach ($rawDatum as $key => $value) { foreach ($rawDatum as $key => $value) {
if (strpos($value, "Comment") !== false) { $value = strtolower($value);
if (str_contains($value, "comment")) {
$commentKey = $key; $commentKey = $key;
} }
if (strpos($value, "Operation type") !== false) { if (str_contains($value, "operation type")) {
$operationKey = $key; $operationKey = $key;
} }
} }
@@ -27,10 +28,15 @@ class ExanteSheet extends SheetDataAll
if ($index<2) { if ($index<2) {
continue; continue;
} }
if (strtolower($rawDatum[$operationKey]) === "tax") { $operationType = strtolower($rawDatum[$operationKey]);
if (!str_contains($operationType,"dividend")) {
continue; continue;
} }
$comment = $rawDatum[$commentKey]; $comment = $rawDatum[$commentKey];
if (!str_contains($comment, "dividend")) {
continue;
}
$separate = explode(" ",$comment); $separate = explode(" ",$comment);
$tax = intval(str_replace(["(","-","%",")"],"",$separate[16])); $tax = intval(str_replace(["(","-","%",")"],"",$separate[16]));
$value = floatval(str_replace(["(",")"],"",$separate[10])); $value = floatval(str_replace(["(",")"],"",$separate[10]));
@@ -44,10 +50,6 @@ class ExanteSheet extends SheetDataAll
$dividendObj->setValue($value); $dividendObj->setValue($value);
$ret[] = $dividendObj; $ret[] = $dividendObj;
} }
if ($commentKey === -1) {
trigger_error(var_export("false",true));
return [];
}
return $ret; return $ret;
} }
+13 -3
View File
@@ -28,9 +28,8 @@ class IbkrSheet extends SheetDataAll
$dividendArr = []; $dividendArr = [];
$taxArr = []; $taxArr = [];
$test = []; $test = [];
foreach ($this->getRawData() as $index => $rawDatum) { foreach ($this->getRawData() as $index => $rawDatum) {
if ($index < 1) { if ($index < 2) {
continue; continue;
} }
$row=[]; $row=[];
@@ -50,18 +49,29 @@ class IbkrSheet extends SheetDataAll
} }
} }
} }
foreach ($dividendArr as $groupId => $dividend) { foreach ($dividendArr as $groupId => $dividend) {
if (!isset($taxArr[$groupId])) {
continue;
}
$taxGet = $taxArr[$groupId]['amount']; $taxGet = $taxArr[$groupId]['amount'];
// $dividend['amount'] += $taxGet; // $dividend['amount'] += $taxGet;
$taxPercentage = intval(round(abs($taxGet) / $dividend['amount'], 2) * 100); $taxPercentage = intval(round(abs($taxGet) / $dividend['amount'], 2) * 100);
if ($taxPercentage === 14) {
$taxPercentage = 15;
}
$separate = explode(" ", $dividend['description']); $separate = explode(" ", $dividend['description']);
$perShare = floatval($separate[4]); $perShare = floatval($separate[4]);
if (!$perShare) { if (!$perShare) {
$perShare = floatval($separate[5]); $perShare = floatval($separate[5]);
} }
if (!$perShare) {
continue;
}
$date = explode(";", $dividend['date'])[0]; $date = explode(";", $dividend['date'])[0];
if (substr_count($date, "-") !== 2) {
$date = substr($date, 0, 4) . "-" . substr($date, 4, 2) . "-" . substr($date, 6, 2); $date = substr($date, 0, 4) . "-" . substr($date, 4, 2) . "-" . substr($date, 6, 2);
}
// trigger_error(var_export($date,true));
$dividendObj = new DividendsData(); $dividendObj = new DividendsData();
$dividendObj->setCount(intval($dividend['amount'] / $perShare)); $dividendObj->setCount(intval($dividend['amount'] / $perShare));
$dividendObj->setIsin($dividend['isin']); $dividendObj->setIsin($dividend['isin']);
@@ -2,6 +2,8 @@
namespace App\Logic\Dividends; namespace App\Logic\Dividends;
use function Symfony\Component\Translation\t;
abstract class SheetDataAll abstract class SheetDataAll
{ {
protected int $countData; protected int $countData;
+13 -6
View File
@@ -2,6 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Services; namespace App\Services;
use App\Enum\MarketNames;
use App\Helper\Sheets\ReadSheet; use App\Helper\Sheets\ReadSheet;
use App\Logic\Dividends\DividendsSummary; use App\Logic\Dividends\DividendsSummary;
use App\Logic\Dividends\ExanteSheet; use App\Logic\Dividends\ExanteSheet;
@@ -18,21 +19,27 @@ class DividendsService extends MasterServices
foreach ($this->allFiles as $file) { foreach ($this->allFiles as $file) {
$extension = pathinfo($file)['extension']; $extension = pathinfo($file)['extension'];
$isExante = strpos($file, "exante") !== false; $market = MarketNames::tryFromCase($file);
$isIbkr = strpos($file, "ibkr") !== false;
$isExante = str_contains($file, "exante");
$isIbkr = str_contains($file, "ibkr");
if (in_array($extension, ['xlsx','csv'])) { if (in_array($extension, ['xlsx','csv'])) {
if ($isExante) { if ($market === MarketNames::EXANTE) {
$delimiter = ";"; $delimiter = ";";
$delimiter = null;
} else { } else {
$delimiter = null; $delimiter = null;
} }
$reader = new ReadSheet($file); $reader = new ReadSheet($file, $market);
if ($reader->takeFile($delimiter)) { if ($reader->takeFile($delimiter)) {
/** @var SheetData $item */ /** @var SheetData $item */
foreach ($reader->getAll() as $val) { foreach ($reader->getAll() as $val) {
if ($isExante) { if ($market === MarketNames::EXANTE) {
$item = new ExanteSheet($val); $item = new ExanteSheet($val);
} elseif ($isIbkr) { } elseif ($market === MarketNames::IBKR) {
$item = new IbkrSheet($val); $item = new IbkrSheet($val);
} }
else { else {
+4 -4
View File
@@ -82,13 +82,13 @@
{% if errorDividend %} {% if errorDividend %}
<table class="table table-dark table-striped"> <table class="table table-dark table-striped">
<tr> <tr>
{% for curr,val in errorDividend %} {% for row in errorDividend %}
<td>{{ curr }}</td> <td>{{ row.currency }}</td>
{% endfor %} {% endfor %}
</tr> </tr>
<tr> <tr>
{% for curr,val in errorDividend %} {% for row in errorDividend %}
<td>{{ val }}</td> <td>{{ row.value }}</td>
{% endfor %} {% endfor %}
</tr> </tr>
</table> </table>
+7 -8
View File
@@ -1,13 +1,12 @@
FROM php:7.4-fpm FROM php:8.1-fpm
RUN apt-get update -y \ RUN apt-get update -y \
&& apt-get install -y nginx \ && apt-get install -y nginx \
&& apt-get install -y libpq-dev && apt-get install -y libpq-dev
RUN pecl install redis-5.1.1 \ RUN pecl install redis \
&& pecl install xdebug-2.8.1 \ && docker-php-ext-enable redis
&& docker-php-ext-enable redis xdebug
RUN apt-get update && apt-get -y install curl RUN apt-get update && apt-get -y install curl
@@ -61,9 +60,9 @@ COPY --chown=www-data:www-data ./project /var/www/html
#COPY --from=minimalise --chown=www-data /var/www/html/src/scripts_generated /var/www/html/src/scripts_generated #COPY --from=minimalise --chown=www-data /var/www/html/src/scripts_generated /var/www/html/src/scripts_generated
WORKDIR /var/www/html WORKDIR /var/www/html
RUN composer install #RUN composer install
RUN npm install #RUN npm install
RUN npm run build #RUN npm run build
RUN apt-get purge --auto-remove -y npm #RUN apt-get purge --auto-remove -y npm
ENTRYPOINT ["/etc/entrypoint.sh"] ENTRYPOINT ["/etc/entrypoint.sh"]