From 68b446db1841f82e135dc11de13aae160c8e20b6 Mon Sep 17 00:00:00 2001 From: James Cole Date: Fri, 27 Dec 2024 19:46:40 +0100 Subject: [PATCH] Final changes. --- .../Controllers/Chart/CategoryController.php | 80 +++++----- app/Http/Controllers/DebugController.php | 4 + .../Category/OperationsRepository.php | 151 +++++++++++------- .../Category/WholePeriodChartGenerator.php | 5 +- 4 files changed, 142 insertions(+), 98 deletions(-) diff --git a/app/Http/Controllers/Chart/CategoryController.php b/app/Http/Controllers/Chart/CategoryController.php index 3a2e51a999..91bd8b24e3 100644 --- a/app/Http/Controllers/Chart/CategoryController.php +++ b/app/Http/Controllers/Chart/CategoryController.php @@ -70,24 +70,27 @@ class CategoryController extends Controller public function all(Category $category): JsonResponse { // cache results: - $cache = new CacheProperties(); + $cache = new CacheProperties(); $cache->addProperty('chart.category.all'); $cache->addProperty($category->id); + $cache->addProperty($this->convertToNative); if ($cache->has()) { - return response()->json($cache->get()); + // return response()->json($cache->get()); } /** @var CategoryRepositoryInterface $repository */ - $repository = app(CategoryRepositoryInterface::class); - $start = $repository->firstUseDate($category) ?? $this->getDate(); - $range = app('navigation')->getViewRange(false); - $start = app('navigation')->startOfPeriod($start, $range); - $end = $this->getDate(); + $repository = app(CategoryRepositoryInterface::class); + $start = $repository->firstUseDate($category) ?? $this->getDate(); + $range = app('navigation')->getViewRange(false); + $start = app('navigation')->startOfPeriod($start, $range); + $end = $this->getDate(); /** @var WholePeriodChartGenerator $chartGenerator */ - $chartGenerator = app(WholePeriodChartGenerator::class); - $chartData = $chartGenerator->generate($category, $start, $end); - $data = $this->generator->multiSet($chartData); + $chartGenerator = app(WholePeriodChartGenerator::class); + $chartGenerator->convertToNative = $this->convertToNative; + + $chartData = $chartGenerator->generate($category, $start, $end); + $data = $this->generator->multiSet($chartData); $cache->store($data); return response()->json($data); @@ -104,10 +107,10 @@ class CategoryController extends Controller */ public function frontPage(): JsonResponse { - $start = session('start', today(config('app.timezone'))->startOfMonth()); - $end = session('end', today(config('app.timezone'))->endOfMonth()); + $start = session('start', today(config('app.timezone'))->startOfMonth()); + $end = session('end', today(config('app.timezone'))->endOfMonth()); // chart properties for cache: - $cache = new CacheProperties(); + $cache = new CacheProperties(); $cache->addProperty($start); $cache->addProperty($end); $cache->addProperty($this->convertToNative); @@ -136,10 +139,11 @@ class CategoryController extends Controller $cache->addProperty('chart.category.period'); $cache->addProperty($accounts->pluck('id')->toArray()); $cache->addProperty($category); + $cache->addProperty($this->convertToNative); if ($cache->has()) { - return response()->json($cache->get()); + // return response()->json($cache->get()); } - $data = $this->reportPeriodChart($accounts, $start, $end, $category); + $data = $this->reportPeriodChart($accounts, $start, $end, $category); $cache->store($data); @@ -160,8 +164,8 @@ class CategoryController extends Controller $noCatRepository = app(NoCategoryRepositoryInterface::class); // this gives us all currencies - $expenses = $noCatRepository->listExpenses($start, $end, $accounts); - $income = $noCatRepository->listIncome($start, $end, $accounts); + $expenses = $noCatRepository->listExpenses($start, $end, $accounts); + $income = $noCatRepository->listIncome($start, $end, $accounts); } if (null !== $category) { @@ -169,9 +173,9 @@ class CategoryController extends Controller $opsRepository = app(OperationsRepositoryInterface::class); $categoryId = $category->id; // this gives us all currencies - $collection = new Collection([$category]); - $expenses = $opsRepository->listExpenses($start, $end, $accounts, $collection); - $income = $opsRepository->listIncome($start, $end, $accounts, $collection); + $collection = new Collection([$category]); + $expenses = $opsRepository->listExpenses($start, $end, $accounts, $collection); + $income = $opsRepository->listIncome($start, $end, $accounts, $collection); } $currencies = array_unique(array_merge(array_keys($income), array_keys($expenses))); $periods = app('navigation')->listOfPeriods($start, $end); @@ -185,19 +189,19 @@ class CategoryController extends Controller $inKey = sprintf('%d-in', $currencyId); $chartData[$outKey] = [ - 'label' => sprintf('%s (%s)', (string) trans('firefly.spent'), $currencyInfo['currency_name']), - 'entries' => [], - 'type' => 'bar', - 'backgroundColor' => 'rgba(219, 68, 55, 0.5)', // red - ]; + 'label' => sprintf('%s (%s)', (string) trans('firefly.spent'), $currencyInfo['currency_name']), + 'entries' => [], + 'type' => 'bar', + 'backgroundColor' => 'rgba(219, 68, 55, 0.5)', // red + ]; $chartData[$inKey] - = [ - 'label' => sprintf('%s (%s)', (string) trans('firefly.earned'), $currencyInfo['currency_name']), - 'entries' => [], - 'type' => 'bar', - 'backgroundColor' => 'rgba(0, 141, 76, 0.5)', // green - ]; + = [ + 'label' => sprintf('%s (%s)', (string) trans('firefly.earned'), $currencyInfo['currency_name']), + 'entries' => [], + 'type' => 'bar', + 'backgroundColor' => 'rgba(0, 141, 76, 0.5)', // green + ]; // loop empty periods: foreach (array_keys($periods) as $period) { $label = $periods[$period]; @@ -205,7 +209,7 @@ class CategoryController extends Controller $chartData[$inKey]['entries'][$label] = '0'; } // loop income and expenses for this category.: - $outSet = $expenses[$currencyId]['categories'][$categoryId] ?? ['transaction_journals' => []]; + $outSet = $expenses[$currencyId]['categories'][$categoryId] ?? ['transaction_journals' => []]; foreach ($outSet['transaction_journals'] as $journal) { $amount = app('steam')->positive($journal['amount']); $date = $journal['date']->isoFormat($format); @@ -214,7 +218,7 @@ class CategoryController extends Controller $chartData[$outKey]['entries'][$date] = bcadd($amount, $chartData[$outKey]['entries'][$date]); } - $inSet = $income[$currencyId]['categories'][$categoryId] ?? ['transaction_journals' => []]; + $inSet = $income[$currencyId]['categories'][$categoryId] ?? ['transaction_journals' => []]; foreach ($inSet['transaction_journals'] as $journal) { $amount = app('steam')->positive($journal['amount']); $date = $journal['date']->isoFormat($format); @@ -240,7 +244,7 @@ class CategoryController extends Controller if ($cache->has()) { return response()->json($cache->get()); } - $data = $this->reportPeriodChart($accounts, $start, $end, null); + $data = $this->reportPeriodChart($accounts, $start, $end, null); $cache->store($data); @@ -255,14 +259,14 @@ class CategoryController extends Controller */ public function specificPeriod(Category $category, Carbon $date): JsonResponse { - $range = app('navigation')->getViewRange(false); - $start = app('navigation')->startOfPeriod($date, $range); - $end = session()->get('end'); + $range = app('navigation')->getViewRange(false); + $start = app('navigation')->startOfPeriod($date, $range); + $end = session()->get('end'); if ($end < $start) { [$end, $start] = [$start, $end]; } - $cache = new CacheProperties(); + $cache = new CacheProperties(); $cache->addProperty($start); $cache->addProperty($end); $cache->addProperty($category->id); diff --git a/app/Http/Controllers/DebugController.php b/app/Http/Controllers/DebugController.php index e08bbe706f..510a4ca910 100644 --- a/app/Http/Controllers/DebugController.php +++ b/app/Http/Controllers/DebugController.php @@ -76,6 +76,10 @@ class DebugController extends Controller || str_starts_with($route->uri(), '_debugbar') || str_starts_with($route->uri(), '_ignition') || str_starts_with($route->uri(), 'oauth') + || str_starts_with($route->uri(), 'chart') + || str_starts_with($route->uri(), 'v1/jscript') + || str_starts_with($route->uri(), 'v2/jscript') + || str_starts_with($route->uri(), 'json') || str_starts_with($route->uri(), 'sanctum') ) { continue; diff --git a/app/Repositories/Category/OperationsRepository.php b/app/Repositories/Category/OperationsRepository.php index 5f62bf2433..6741f3ffa8 100644 --- a/app/Repositories/Category/OperationsRepository.php +++ b/app/Repositories/Category/OperationsRepository.php @@ -63,13 +63,13 @@ class OperationsRepository implements OperationsRepositoryInterface $collector->setCategories($this->getCategories()); } $collector->withCategoryInformation()->withAccountInformation()->withBudgetInformation(); - $journals = $collector->getExtractedJournals(); - $array = []; + $journals = $collector->getExtractedJournals(); + $array = []; foreach ($journals as $journal) { - $currencyId = (int) $journal['currency_id']; - $categoryId = (int) $journal['category_id']; - $categoryName = (string) $journal['category_name']; + $currencyId = (int) $journal['currency_id']; + $categoryId = (int) $journal['category_id']; + $categoryName = (string) $journal['category_name']; // catch "no category" entries. if (0 === $categoryId) { @@ -77,7 +77,7 @@ class OperationsRepository implements OperationsRepositoryInterface } // info about the currency: - $array[$currencyId] ??= [ + $array[$currencyId] ??= [ 'categories' => [], 'currency_id' => (string) $currencyId, 'currency_name' => $journal['currency_name'], @@ -112,7 +112,7 @@ class OperationsRepository implements OperationsRepositoryInterface return $array; } - public function setUser(null|Authenticatable|User $user): void + public function setUser(null | Authenticatable | User $user): void { if ($user instanceof User) { $this->user = $user; @@ -147,13 +147,13 @@ class OperationsRepository implements OperationsRepositoryInterface $collector->setCategories($this->getCategories()); } $collector->withCategoryInformation()->withAccountInformation(); - $journals = $collector->getExtractedJournals(); - $array = []; + $journals = $collector->getExtractedJournals(); + $array = []; foreach ($journals as $journal) { - $currencyId = (int) $journal['currency_id']; - $categoryId = (int) $journal['category_id']; - $categoryName = (string) $journal['category_name']; + $currencyId = (int) $journal['currency_id']; + $categoryId = (int) $journal['category_id']; + $categoryName = (string) $journal['category_name']; // catch "no category" entries. if (0 === $categoryId) { @@ -161,7 +161,7 @@ class OperationsRepository implements OperationsRepositoryInterface } // info about the currency: - $array[$currencyId] ??= [ + $array[$currencyId] ??= [ 'categories' => [], 'currency_id' => (string) $currencyId, 'currency_name' => $journal['currency_name'], @@ -200,8 +200,7 @@ class OperationsRepository implements OperationsRepositoryInterface /** @var GroupCollectorInterface $collector */ $collector = app(GroupCollectorInterface::class); $collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionType::TRANSFER]) - ->setDestinationAccounts($accounts)->excludeSourceAccounts($accounts) - ; + ->setDestinationAccounts($accounts)->excludeSourceAccounts($accounts); if (null !== $categories && $categories->count() > 0) { $collector->setCategories($categories); } @@ -209,13 +208,13 @@ class OperationsRepository implements OperationsRepositoryInterface $collector->setCategories($this->getCategories()); } $collector->withCategoryInformation()->withAccountInformation()->withBudgetInformation(); - $journals = $collector->getExtractedJournals(); - $array = []; + $journals = $collector->getExtractedJournals(); + $array = []; foreach ($journals as $journal) { - $currencyId = (int) $journal['currency_id']; - $categoryId = (int) $journal['category_id']; - $categoryName = (string) $journal['category_name']; + $currencyId = (int) $journal['currency_id']; + $categoryId = (int) $journal['category_id']; + $categoryName = (string) $journal['category_name']; // catch "no category" entries. if (0 === $categoryId) { @@ -223,7 +222,7 @@ class OperationsRepository implements OperationsRepositoryInterface } // info about the currency: - $array[$currencyId] ??= [ + $array[$currencyId] ??= [ 'categories' => [], 'currency_id' => (string) $currencyId, 'currency_name' => $journal['currency_name'], @@ -263,8 +262,7 @@ class OperationsRepository implements OperationsRepositoryInterface /** @var GroupCollectorInterface $collector */ $collector = app(GroupCollectorInterface::class); $collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionType::TRANSFER]) - ->setSourceAccounts($accounts)->excludeDestinationAccounts($accounts) - ; + ->setSourceAccounts($accounts)->excludeDestinationAccounts($accounts); if (null !== $categories && $categories->count() > 0) { $collector->setCategories($categories); } @@ -272,13 +270,13 @@ class OperationsRepository implements OperationsRepositoryInterface $collector->setCategories($this->getCategories()); } $collector->withCategoryInformation()->withAccountInformation()->withBudgetInformation(); - $journals = $collector->getExtractedJournals(); - $array = []; + $journals = $collector->getExtractedJournals(); + $array = []; foreach ($journals as $journal) { - $currencyId = (int) $journal['currency_id']; - $categoryId = (int) $journal['category_id']; - $categoryName = (string) $journal['category_name']; + $currencyId = (int) $journal['currency_id']; + $categoryId = (int) $journal['category_id']; + $categoryName = (string) $journal['category_name']; // catch "no category" entries. if (0 === $categoryId) { @@ -286,7 +284,7 @@ class OperationsRepository implements OperationsRepositoryInterface } // info about the currency: - $array[$currencyId] ??= [ + $array[$currencyId] ??= [ 'categories' => [], 'currency_id' => (string) $currencyId, 'currency_name' => $journal['currency_name'], @@ -327,7 +325,7 @@ class OperationsRepository implements OperationsRepositoryInterface public function sumExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array { /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollectorInterface::class); + $collector = app(GroupCollectorInterface::class); $collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionTypeEnum::WITHDRAWAL->value]); // default currency information for native stuff. @@ -341,29 +339,35 @@ class OperationsRepository implements OperationsRepositoryInterface } $collector->setCategories($categories); $collector->withCategoryInformation(); - $journals = $collector->getExtractedJournals(); - $array = []; + $journals = $collector->getExtractedJournals(); + $array = []; Log::debug(sprintf('Collected %d journals', count($journals))); foreach ($journals as $journal) { // Almost the same as in \FireflyIII\Repositories\Budget\OperationsRepository::sumExpenses - $amount = '0'; - $currencyId = (int) $journal['currency_id']; - $currencyName = $journal['currency_name']; - $currencySymbol = $journal['currency_symbol']; - $currencyCode = $journal['currency_code']; - $currencyDecimalPlaces = $journal['currency_decimal_places']; + $amount = '0'; + $currencyId = (int) $journal['currency_id']; + $currencyName = $journal['currency_name']; + $currencySymbol = $journal['currency_symbol']; + $currencyCode = $journal['currency_code']; + $currencyDecimalPlaces = $journal['currency_decimal_places']; if ($convertToNative) { - $useNative = $default->id !== (int) $journal['currency_id']; - $amount = Amount::getAmountFromJournal($journal); - if ($useNative) { + $amount = Amount::getAmountFromJournal($journal); + if ($default->id !== (int) $journal['currency_id'] && $default->id !== (int) $journal['foreign_currency_id']) { $currencyId = $default->id; $currencyName = $default->name; $currencySymbol = $default->symbol; $currencyCode = $default->code; $currencyDecimalPlaces = $default->decimal_places; } + if ($default->id !== (int) $journal['currency_id'] && $default->id === (int) $journal['foreign_currency_id']) { + $currencyId = $journal['foreign_currency_id']; + $currencyName = $journal['foreign_currency_name']; + $currencySymbol = $journal['foreign_currency_symbol']; + $currencyCode = $journal['foreign_currency_code']; + $currencyDecimalPlaces = $journal['foreign_currency_decimal_places']; + } Log::debug(sprintf('[a] Add amount %s %s', $currencyCode, $amount)); } if (!$convertToNative) { @@ -372,8 +376,7 @@ class OperationsRepository implements OperationsRepositoryInterface $amount = $journal['amount']; } - - $array[$currencyId] ??= [ + $array[$currencyId] ??= [ 'sum' => '0', 'currency_id' => (string) $currencyId, 'currency_name' => $currencyName, @@ -395,8 +398,7 @@ class OperationsRepository implements OperationsRepositoryInterface /** @var GroupCollectorInterface $collector */ $collector = app(GroupCollectorInterface::class); $collector->setUser($this->user)->setRange($start, $end) - ->setTypes([TransactionType::DEPOSIT]) - ; + ->setTypes([TransactionTypeEnum::DEPOSIT->value]); if (null !== $accounts && $accounts->count() > 0) { $collector->setAccounts($accounts); @@ -405,20 +407,52 @@ class OperationsRepository implements OperationsRepositoryInterface $categories = $this->getCategories(); } $collector->setCategories($categories); - $journals = $collector->getExtractedJournals(); - $array = []; + $journals = $collector->getExtractedJournals(); + $convertToNative = app('preferences')->get('convert_to_native', false)->data; + $default = app('amount')->getDefaultCurrency(); + $array = []; foreach ($journals as $journal) { - $currencyId = (int) $journal['currency_id']; - $array[$currencyId] ??= [ + // Almost the same as in \FireflyIII\Repositories\Budget\OperationsRepository::sumExpenses + $amount = '0'; + $currencyId = (int) $journal['currency_id']; + $currencyName = $journal['currency_name']; + $currencySymbol = $journal['currency_symbol']; + $currencyCode = $journal['currency_code']; + $currencyDecimalPlaces = $journal['currency_decimal_places']; + if ($convertToNative) { + $amount = Amount::getAmountFromJournal($journal); + if ($default->id !== (int) $journal['currency_id'] && $default->id !== (int) $journal['foreign_currency_id']) { + $currencyId = $default->id; + $currencyName = $default->name; + $currencySymbol = $default->symbol; + $currencyCode = $default->code; + $currencyDecimalPlaces = $default->decimal_places; + } + if ($default->id !== (int) $journal['currency_id'] && $default->id === (int) $journal['foreign_currency_id']) { + $currencyId = $journal['foreign_currency_id']; + $currencyName = $journal['foreign_currency_name']; + $currencySymbol = $journal['foreign_currency_symbol']; + $currencyCode = $journal['foreign_currency_code']; + $currencyDecimalPlaces = $journal['foreign_currency_decimal_places']; + } + Log::debug(sprintf('[a] Add amount %s %s', $currencyCode, $amount)); + } + if (!$convertToNative) { + // ignore the amount in foreign currency. + Log::debug(sprintf('[b] Add amount %s %s', $currencyCode, $journal['amount'])); + $amount = $journal['amount']; + } + + $array[$currencyId] ??= [ 'sum' => '0', 'currency_id' => (string) $currencyId, - 'currency_name' => $journal['currency_name'], - 'currency_symbol' => $journal['currency_symbol'], - 'currency_code' => $journal['currency_code'], - 'currency_decimal_places' => $journal['currency_decimal_places'], + 'currency_name' => $currencyName, + 'currency_symbol' => $currencySymbol, + 'currency_code' => $currencyCode, + 'currency_decimal_places' => $currencyDecimalPlaces, ]; - $array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->positive($journal['amount'])); + $array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->positive($amount)); } return $array; @@ -432,8 +466,7 @@ class OperationsRepository implements OperationsRepositoryInterface /** @var GroupCollectorInterface $collector */ $collector = app(GroupCollectorInterface::class); $collector->setUser($this->user)->setRange($start, $end) - ->setTypes([TransactionType::TRANSFER]) - ; + ->setTypes([TransactionType::TRANSFER]); if (null !== $accounts && $accounts->count() > 0) { $collector->setAccounts($accounts); @@ -442,12 +475,12 @@ class OperationsRepository implements OperationsRepositoryInterface $categories = $this->getCategories(); } $collector->setCategories($categories); - $journals = $collector->getExtractedJournals(); - $array = []; + $journals = $collector->getExtractedJournals(); + $array = []; foreach ($journals as $journal) { $currencyId = (int) $journal['currency_id']; - $array[$currencyId] ??= [ + $array[$currencyId] ??= [ 'sum' => '0', 'currency_id' => (string) $currencyId, 'currency_name' => $journal['currency_name'], diff --git a/app/Support/Chart/Category/WholePeriodChartGenerator.php b/app/Support/Chart/Category/WholePeriodChartGenerator.php index 1a562aa370..2b2e39b182 100644 --- a/app/Support/Chart/Category/WholePeriodChartGenerator.php +++ b/app/Support/Chart/Category/WholePeriodChartGenerator.php @@ -25,6 +25,7 @@ declare(strict_types=1); namespace FireflyIII\Support\Chart\Category; use Carbon\Carbon; +use FireflyIII\Enums\AccountTypeEnum; use FireflyIII\Models\AccountType; use FireflyIII\Models\Category; use FireflyIII\Repositories\Account\AccountRepositoryInterface; @@ -36,6 +37,8 @@ use Illuminate\Support\Collection; */ class WholePeriodChartGenerator { + public bool $convertToNative; + public function generate(Category $category, Carbon $start, Carbon $end): array { $collection = new Collection([$category]); @@ -46,7 +49,7 @@ class WholePeriodChartGenerator /** @var AccountRepositoryInterface $accountRepository */ $accountRepository = app(AccountRepositoryInterface::class); - $types = [AccountType::DEFAULT, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]; + $types = [AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value]; $accounts = $accountRepository->getAccountsByType($types); $step = $this->calculateStep($start, $end); $chartData = [];