diff --git a/project/src/Controller/TaxesController.php b/project/src/Controller/TaxesController.php index ac4e939..73671e2 100644 --- a/project/src/Controller/TaxesController.php +++ b/project/src/Controller/TaxesController.php @@ -3,6 +3,7 @@ namespace App\Controller; use App\Helper\Currency; +use App\Helper\DataNeed\NeedFileName; use App\Services\CryptoService; use App\Services\DividendsService; use PhpOffice\PhpSpreadsheet\Reader\Xlsx; @@ -67,9 +68,14 @@ class TaxesController extends AbstractController $i=1; /** @var UploadedFile $file */ foreach ($files as $file) { + $newName = $i; + $checkName = NeedFileName::check($file->getClientOriginalName()); + if ($checkName !== null) { + $newName .= "-".$checkName; + } $file->move( $this->getParameter("uploads_path")."/".$hash, - $i.".".$file->getClientOriginalExtension() + $newName.".".$file->getClientOriginalExtension() ); $i++; } @@ -94,7 +100,9 @@ class TaxesController extends AbstractController // dd($gen); return $this->render("taxes/show.html.twig", [ "taxes" => $gen->getSummaryByCountry(), - "error" => $gen->error + "errorDividend" => $gen->getErrorDividend(), + "errorString" => $gen->getErrorString(), + "rawCount" => $gen->takeCountRawData() ]); } diff --git a/project/src/Helper/Currency.php b/project/src/Helper/Currency.php index 179070e..a35ada7 100644 --- a/project/src/Helper/Currency.php +++ b/project/src/Helper/Currency.php @@ -7,7 +7,7 @@ use Doctrine\ORM\EntityManager; class Currency { - public static array $currencies = ["USD","GBP","PLN","EUR"]; + public static array $currencies = ["USD","GBP","PLN","EUR","CAD"]; public static array $currenciesCrypto = ["USDT"]; private static string $apiUrl = "https://api.nbp.pl/api/exchangerates/rates/a/:code/:date/?format=json"; private EntityManager $manager; @@ -19,7 +19,7 @@ class Currency $this->takeRates(); } - public function getRate(string $currency, \DateTime $dateTime, &$err) : float + public function getRate(string $currency, \DateTime $dateTime) : float { $dayOfWeek = $dateTime->format("N"); $minusDay = 1; @@ -35,12 +35,16 @@ class Currency return $this->ratesPerDate[$currency][$dateStr]; } $dateCopy = clone $dateTime; - + $limitLoop = 5; do { $rate = $this->takePLNOnDate($currency, $dateCopy->format("Y-m-d")); if (!$rate) { $dateCopy->modify("-1 day"); } + if ($limitLoop < 1) { + break; + } + $limitLoop--; }while($rate == 0); if ($rate) { @@ -61,7 +65,7 @@ class Currency private function takePLNOnDate(string $currency, string $dateStr) : float { - if (!in_array($currency, self::$currencies)) { + if (!self::isCurrencyExists($currency)) { return 0; } $url = strtr(self::$apiUrl,[ @@ -95,4 +99,10 @@ class Currency } } } + + + public static function isCurrencyExists(string $currency) : bool + { + return in_array($currency, self::$currencies); + } } \ No newline at end of file diff --git a/project/src/Helper/DataNeed/CryptoValues.php b/project/src/Helper/DataNeed/CryptoValues.php index 00499ff..eeeb288 100644 --- a/project/src/Helper/DataNeed/CryptoValues.php +++ b/project/src/Helper/DataNeed/CryptoValues.php @@ -12,8 +12,8 @@ final class CryptoValues "date" => ["Data operacji","Date(UTC)"], "desc" => ["Rodzaj"], "price" => ["Price"], - "transactionType" => ["Type"], - "market" => ["Market"], + "transactionType" => ["Type","Side"], + "market" => ["Market","Pair"], "realValue" => ["Total"] ]; diff --git a/project/src/Helper/DataNeed/DividendValues.php b/project/src/Helper/DataNeed/DividendValues.php new file mode 100644 index 0000000..4b2f8c1 --- /dev/null +++ b/project/src/Helper/DataNeed/DividendValues.php @@ -0,0 +1,37 @@ + ["LICZBA POSIADANYCH SZT"], + 'isin' => ["ISIN"], + 'currency' => ["WALUTA","CurrencyPrimary"], + 'tax' => ["PODATK"], + 'value' => ["DYWIDENDA BRUTTO"], + 'date' => ["DATA","Date"], + 'description' => ["Desc"], + 'amount' => ["Amount"], + 'groupId' => ["ActionID"], + 'type' => ["Type"] + ]; + + public static function searchForKeyName(string $val) : ?string + { + $ret=null; + foreach (self::$samples as $key => $sample) { + foreach ($sample as $item) { + if (strpos($val, $item) !== false) { + $ret = $key; + break; + } + if ($ret) { + break; + } + } + } + + return $ret; + } +} \ No newline at end of file diff --git a/project/src/Helper/DataNeed/NeedFileName.php b/project/src/Helper/DataNeed/NeedFileName.php new file mode 100644 index 0000000..cbbcc1a --- /dev/null +++ b/project/src/Helper/DataNeed/NeedFileName.php @@ -0,0 +1,23 @@ +getRealCurrency()])) { + continue; + } if (!($curr instanceof MainObject)) { $curr = $realCurrency[$item->getRealCurrency()][array_key_first($realCurrency[$item->getRealCurrency()])]; } diff --git a/project/src/Helper/FIFO/Main.php b/project/src/Helper/FIFO/Main.php index 0d3bdb8..1658701 100644 --- a/project/src/Helper/FIFO/Main.php +++ b/project/src/Helper/FIFO/Main.php @@ -17,15 +17,15 @@ class Main public function addData(array $data) { if (isset($data[0]) && $data[0][0]==='Date(UTC)') { - $first = array_shift($data); - array_unshift($data, $first, [ - "2021-04-14 13:00:00", - "EURPLN", - "BUY", - 4.5755, - 100, - 457.55 - ]); +// $first = array_shift($data); +// array_unshift($data, $first, [ +// "2021-04-14 13:00:00", +// "EURPLN", +// "BUY", +// 4.5755, +// 100, +// 457.55 +// ]); } $this->data[] = $data; } @@ -87,6 +87,13 @@ class Main if ($name === "setRealValue") { $datum[$key] = intval($datum[$key]*100); } + if ($name === "setPrice" && is_string($datum[$key])) { + $val = $datum[$key]; + if (strpos($val, ".") !== false && strpos($val, ",") !== false) { + $val = str_replace(",", "", $val); + $datum[$key] = intval(floatval($val)*100); + } + } $obj->$name($datum[$key]); } $obj->trySetCurrencies(); diff --git a/project/src/Helper/Sheets/ReadSheet.php b/project/src/Helper/Sheets/ReadSheet.php index a4a410e..8c84787 100644 --- a/project/src/Helper/Sheets/ReadSheet.php +++ b/project/src/Helper/Sheets/ReadSheet.php @@ -21,17 +21,21 @@ class ReadSheet return $this->arr; } - public function takeFile() : bool + public function takeFile(?string $delimiter = null) : bool { if (!$this->filePath) { return false; } - $fileType = explode(".", $this->filePath); + $fileType = explode(".", $this->filePath)[1]; - $reader = IOFactory::createReader(ucfirst($fileType[1])); + $reader = IOFactory::createReader(ucfirst($fileType)); $reader->setLoadAllSheets(); $reader->setReadDataOnly(true); + if ($delimiter) { + $reader->setDelimiter($delimiter); + } $spreadsheet = $reader->load($this->filePath); +// $spreadsheet->getDefaultStyle()->getNumberFormat()->setFormatCode('@'); foreach ($spreadsheet->getAllSheets() as $sheetName) { $this->arr[] = $sheetName->toArray(); } diff --git a/project/src/Logic/Crypto/MainObject.php b/project/src/Logic/Crypto/MainObject.php index d7d7fbd..23854e8 100644 --- a/project/src/Logic/Crypto/MainObject.php +++ b/project/src/Logic/Crypto/MainObject.php @@ -209,6 +209,7 @@ class MainObject public function trySetCurrencies() : void { if ($this->marketName) { + $cryptoFiat = ["USDT","BUSD"]; if (strlen($this->marketName) === 6) { $cur1 = substr($this->marketName,0,3); $cur2 = substr($this->marketName,3); @@ -221,7 +222,6 @@ class MainObject $this->setRealCurrency($cur1); } } else { - $cryptoFiat = ["USDT"]; foreach ($cryptoFiat as $item) { $currReal = strpos($this->marketName, $item); if ($currReal === false) { diff --git a/project/src/Logic/Dividends/DividendsSummary.php b/project/src/Logic/Dividends/DividendsSummary.php index 6b86186..fb39b62 100644 --- a/project/src/Logic/Dividends/DividendsSummary.php +++ b/project/src/Logic/Dividends/DividendsSummary.php @@ -7,14 +7,17 @@ use Doctrine\ORM\EntityManager; class DividendsSummary { - /** @var SheetData|array $sheetData */ + /** @var SheetDataAll|array $sheetData */ private array $sheetData=[]; /** @var XMLReader|array $sheetData */ private array $xmlData=[]; private Currency $currencyObj; - public array $error=[]; + /** @var array|DividendsData $error */ + private ?array $errorDividend=null; + private ?array $errorString=null; private array $allData=[]; private array $countryToCurrency=[]; + private int $realCalculatedRows = 0; public function __construct(EntityManager $manager) { @@ -88,6 +91,7 @@ class DividendsSummary if (!isset($countryToCurrency[$country])) { $countryToCurrency[$country] = $val->getCurrency(); } + $this->realCalculatedRows++; } } } @@ -101,7 +105,11 @@ class DividendsSummary private function getRate(DividendsData $data) : float { - return $this->currencyObj->getRate($data->getCurrency(),$data->getDateTime(),$this->error); + if (!Currency::isCurrencyExists($data->getCurrency())) { + $this->errorString[$data->getCurrency()] = "Currency: {$data->getCurrency()} is not supported! Please contact with administrator."; + return 0; + } + return $this->currencyObj->getRate($data->getCurrency(),$data->getDateTime()); } private function count(DividendsData $data, bool $fromDestiny = false) : float @@ -120,7 +128,7 @@ class DividendsSummary if ($rate > 0) { return $valueTax * $rate; } - $this->error[]=$data; + $this->errorDividend[]=$data; return 0; } @@ -140,9 +148,9 @@ class DividendsSummary } /** - * @param SheetData $sheetData + * @param SheetDataAll $sheetData */ - public function addSheetData(SheetData $sheetData): void + public function addSheetData(SheetDataAll $sheetData): void { $this->sheetData[] = $sheetData; } @@ -155,4 +163,27 @@ class DividendsSummary $this->xmlData[] = $reader; } + public function takeCountRawData(): array + { + $rowCount = 0; + /** @var SheetData $sheetDatum */ + foreach ($this->sheetData as $sheetDatum) { + $rowCount += $sheetDatum->getCount(); + } + return [ + 'countSheet' => count($this->sheetData), + 'countRows' => $rowCount, + 'realCountRows' => $this->realCalculatedRows + ]; + } + + public function getErrorDividend(): ?array + { + return $this->errorDividend; + } + public function getErrorString(): ?array + { + return $this->errorString; + } + } \ No newline at end of file diff --git a/project/src/Logic/Dividends/ExanteSheet.php b/project/src/Logic/Dividends/ExanteSheet.php new file mode 100644 index 0000000..8ac92b9 --- /dev/null +++ b/project/src/Logic/Dividends/ExanteSheet.php @@ -0,0 +1,54 @@ +getRawData() as $index => $rawDatum) { + if (!isset($rawDatum[1])) { + continue; + } + foreach ($rawDatum as $key => $value) { + if (strpos($value, "Comment") !== false) { + $commentKey = $key; + } + if (strpos($value, "Operation type") !== false) { + $operationKey = $key; + } + } + break; + } + foreach ($this->getRawData() as $index => $rawDatum) { + if ($index<2) { + continue; + } + if (strtolower($rawDatum[$operationKey]) === "tax") { + continue; + } + $comment = $rawDatum[$commentKey]; + $separate = explode(" ",$comment); + $tax = intval(str_replace(["(","-","%",")"],"",$separate[16])); + $value = floatval(str_replace(["(",")"],"",$separate[10])); + $date = new \DateTime($separate[3]); + $dividendObj = new DividendsData(); + $dividendObj->setCount($separate[0]); + $dividendObj->setCurrency($separate[9]); + $dividendObj->setTax($tax); + $dividendObj->setDateTime($date); + $dividendObj->setIsin($separate[18]); + $dividendObj->setValue($value); + $ret[] = $dividendObj; + } + if ($commentKey === -1) { + trigger_error(var_export("false",true)); + return []; + } + + return $ret; + } +} \ No newline at end of file diff --git a/project/src/Logic/Dividends/IbkrSheet.php b/project/src/Logic/Dividends/IbkrSheet.php new file mode 100644 index 0000000..fa51e59 --- /dev/null +++ b/project/src/Logic/Dividends/IbkrSheet.php @@ -0,0 +1,78 @@ +getRawData() as $index => $rawDatum) { + if ($index === 0) { + foreach ($rawDatum as $i => $item) { + if (!$item) { + continue; + } + $keyName = DividendValues::searchForKeyName($item); + if ($keyName) { + $needIndex[$i] = $keyName; + } + } + break; + } + } + + $ret = []; + $dividendArr = []; + $taxArr = []; + $test = []; + + foreach ($this->getRawData() as $index => $rawDatum) { + if ($index < 1) { + continue; + } + $row=[]; + foreach ($rawDatum as $i => $d) { + if (isset($needIndex[$i])) { + $row[$needIndex[$i]] = $d; + } + } + $test[$row['groupId']][] = $row['amount']; + if (strpos($row['type'], "Dividend") !== false) { + $dividendArr[$row['groupId']] = $row; + } else { + if (!isset($taxArr[$row['groupId']])) { + $taxArr[$row['groupId']] = $row; + } else { + $taxArr[$row['groupId']]['amount'] += $row['amount']; + } + } + } + + foreach ($dividendArr as $groupId => $dividend) { + $taxGet = $taxArr[$groupId]['amount']; +// $dividend['amount'] += $taxGet; + $taxPercentage = intval(round(abs($taxGet) / $dividend['amount'], 2) * 100); + $separate = explode(" ", $dividend['description']); + $perShare = floatval($separate[4]); + if (!$perShare) { + $perShare = floatval($separate[5]); + } + $date = explode(";", $dividend['date'])[0]; + $date = substr($date, 0, 4) . "-" . substr($date, 4, 2) . "-" . substr($date, 6, 2); + $dividendObj = new DividendsData(); + $dividendObj->setCount(intval($dividend['amount'] / $perShare)); + $dividendObj->setIsin($dividend['isin']); + $dividendObj->setCurrency($dividend['currency']); + $dividendObj->setTax($taxPercentage); + $dividendObj->setValue($perShare); + $dividendObj->setDateTime(new \DateTime($date)); + + $ret[] = $dividendObj; + } + + return $ret; + } +} \ No newline at end of file diff --git a/project/src/Logic/Dividends/SheetData.php b/project/src/Logic/Dividends/SheetData.php index dbca17e..7d8b82e 100644 --- a/project/src/Logic/Dividends/SheetData.php +++ b/project/src/Logic/Dividends/SheetData.php @@ -3,43 +3,36 @@ declare(strict_types=1); namespace App\Logic\Dividends; use App\Helper\Currency; +use App\Helper\DataNeed\DividendValues; +use PhpOffice\PhpSpreadsheet\Shared\Date; -class SheetData +class SheetData extends SheetDataAll { - private array $rawData; // eg. 0 -> name, 1 -> ISIN private array $dataIndex; - private array $data; - - public function __construct(array $data) - { - $this->rawData = $data; - } - public function get() : array + public function takeData() : array { - if (isset($this->data)) { - return $this->data; - } - $needIndex = []; - foreach ($this->rawData as $index => $rawDatum) { + foreach ($this->getRawData() as $index => $rawDatum) { if ($index === 0) { $this->dataIndex = $rawDatum; - continue; - } - $setDatas=[]; - foreach ($rawDatum as $i => $data) { - $dataType = $this->getDataType($data,$setDatas); - if ($dataType){ - $needIndex[$i] = $dataType; + foreach ($rawDatum as $i => $item) { + if (!$item) { + continue; + } + $keyName = DividendValues::searchForKeyName($item); + if ($keyName) { + $needIndex[$i] = $keyName; + } } + break; +// continue; } - unset($setDatas); - break; +// trigger_error(var_export($rawDatum,true)); } $ret = []; - foreach ($this->rawData as $index => $datum) { + foreach ($this->getRawData() as $index => $datum) { if ($index === 0) { continue; } @@ -49,35 +42,30 @@ class SheetData $row[$needIndex[$i]] = $d; } } + if (count($row) < 1) { + continue; + } + $date = &$row['date']; + if (is_int($date)) { + $date = Date::excelToDateTimeObject($date); + } else if (is_string($date)) { + $date = new \DateTime(str_replace(".", "-", $date)); + } + if (is_float($row['tax'])) { + $row['tax'] = intval(round($row['tax']*100)); + } $dividendObj = new DividendsData(); $dividendObj->setCount($row['count']); $dividendObj->setIsin($row['isin']); $dividendObj->setCurrency($row['currency']); $dividendObj->setTax($row['tax']); $dividendObj->setValue($row['value']); - $dividendObj->setDateTime(new \DateTime(str_replace(".","-",$row['date']))); + $dividendObj->setDateTime($date); $ret[] = $dividendObj; } - $this->data = $ret; return $ret; } - public function getByCountry() : array - { - $data = $this->get(); - if (!$data) { - return []; - } - $newArr = []; - /** @var DividendsData $datum */ - foreach ($data as $datum) { - $key = mb_substr($datum->getIsin(), 0, 2); - $newArr[$key][] = $datum; - } - - return $newArr; - } - public function takeColumnNames() : array { return $this->dataIndex; @@ -118,10 +106,24 @@ class SheetData if (in_array($data, Currency::$currencies)) { return "currency"; } - if (count(explode(".", $data)) === 3) { + if (count(explode(".", $data)) === 3 || count(explode("-", $data)) === 3) { return "date"; } return null; } + + private function searchForDateIndex() : int + { + $ret = -1; + + foreach ($this->takeColumnNames() as $index => $takeColumnName) { + if (strpos($takeColumnName,"DATE") !== false || strpos($takeColumnName,"DATA") !== false) { + $ret = $index; + break; + } + } + + return $ret; + } } diff --git a/project/src/Logic/Dividends/SheetDataAll.php b/project/src/Logic/Dividends/SheetDataAll.php new file mode 100644 index 0000000..a9f2749 --- /dev/null +++ b/project/src/Logic/Dividends/SheetDataAll.php @@ -0,0 +1,83 @@ +rawData = $rawData; + $this->countData = count($this->rawData) - 1; + $this->data = $this->takeData(); + } + + /** + * Get array grouped values by country + * + * @return array + */ + public function getByCountry() : array + { + $data = $this->getData(); + if (!$data) { + return []; + } + $newArr = []; + /** @var DividendsData $datum */ + foreach ($data as $datum) { + $key = mb_substr($datum->getIsin(), 0, 2); + $newArr[$key][] = $datum; + } + + return $newArr; + } + + /** + * Get count of rows + * + * @return int + */ + public function getCount(): int + { + return $this->countData; + } + + /** + * Get array of DividendsData + * + * @return array + */ + protected function getData() : array + { + return $this->data; + } + + /** + * Get array of raw data + * + * @return array + */ + protected function getRawData() : array + { + return $this->rawData; + } + + /** + * Generate array of DividendsData from $rawData + * + * @return array + */ + abstract protected function takeData() : array; +} \ No newline at end of file diff --git a/project/src/Services/DividendsService.php b/project/src/Services/DividendsService.php index e9c3291..3ac877e 100644 --- a/project/src/Services/DividendsService.php +++ b/project/src/Services/DividendsService.php @@ -4,6 +4,8 @@ namespace App\Services; use App\Helper\Sheets\ReadSheet; use App\Logic\Dividends\DividendsSummary; +use App\Logic\Dividends\ExanteSheet; +use App\Logic\Dividends\IbkrSheet; use App\Logic\Dividends\SheetData; use App\Logic\Dividends\XMLReader; use Doctrine\ORM\EntityManager; @@ -16,12 +18,26 @@ class DividendsService extends MasterServices foreach ($this->allFiles as $file) { $extension = pathinfo($file)['extension']; + $isExante = strpos($file, "exante") !== false; + $isIbkr = strpos($file, "ibkr") !== false; if (in_array($extension, ['xlsx','csv'])) { + if ($isExante) { + $delimiter = ";"; + } else { + $delimiter = null; + } $reader = new ReadSheet($file); - if ($reader->takeFile()) { + if ($reader->takeFile($delimiter)) { /** @var SheetData $item */ foreach ($reader->getAll() as $val) { - $item = new SheetData($val); + if ($isExante) { + $item = new ExanteSheet($val); + } elseif ($isIbkr) { + $item = new IbkrSheet($val); + } + else { + $item = new SheetData($val); + } $summaryObj->addSheetData($item); } } diff --git a/project/templates/taxes/show.html.twig b/project/templates/taxes/show.html.twig index a427ffc..d633226 100644 --- a/project/templates/taxes/show.html.twig +++ b/project/templates/taxes/show.html.twig @@ -77,21 +77,29 @@ {% endfor %} + Calculated {{ rawCount.realCountRows }} of {{ rawCount.countRows }} rows in {{ rawCount.countSheet }} sheets {% endif %} - {% if error %} + {% if errorDividend %}
| {{ curr }} | {% endfor %}
| {{ val }} | {% endfor %}