diff --git a/app/Api/V2/Controllers/Controller.php b/app/Api/V2/Controllers/Controller.php index b88983f6d7..d1dc20b5bd 100644 --- a/app/Api/V2/Controllers/Controller.php +++ b/app/Api/V2/Controllers/Controller.php @@ -22,15 +22,22 @@ declare(strict_types=1); namespace FireflyIII\Api\V2\Controllers; +use Carbon\Carbon; +use Carbon\Exceptions\InvalidDateException; +use Carbon\Exceptions\InvalidFormatException; use FireflyIII\Transformers\V2\AbstractTransformer; use Illuminate\Database\Eloquent\Model; use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Routing\Controller as BaseController; +use Illuminate\Support\Collection; use League\Fractal\Manager; use League\Fractal\Pagination\IlluminatePaginatorAdapter; use League\Fractal\Resource\Collection as FractalCollection; use League\Fractal\Resource\Item; use League\Fractal\Serializer\JsonApiSerializer; +use Psr\Container\ContainerExceptionInterface; +use Psr\Container\NotFoundExceptionInterface; +use Symfony\Component\HttpFoundation\ParameterBag; /** * Class Controller @@ -38,14 +45,16 @@ use League\Fractal\Serializer\JsonApiSerializer; class Controller extends BaseController { protected const CONTENT_TYPE = 'application/vnd.api+json'; - protected int $pageSize; + protected int $pageSize; + protected ParameterBag $parameters; /** * */ public function __construct() { - $this->pageSize = 50; + $this->parameters = $this->getParameters(); + $this->pageSize = 50; if (auth()->check()) { $this->pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; } @@ -66,6 +75,8 @@ class Controller extends BaseController $baseUrl = request()->getSchemeAndHttpHost() . '/api/v2'; $manager->setSerializer(new JsonApiSerializer($baseUrl)); + $transformer->collectMetaData(new Collection([$object])); + $resource = new Item($object, $transformer, $key); return $manager->createData($resource)->toArray(); } @@ -82,7 +93,7 @@ class Controller extends BaseController $baseUrl = request()->getSchemeAndHttpHost() . '/api/v2'; $manager->setSerializer(new JsonApiSerializer($baseUrl)); - $objects = $paginator->getCollection(); + $objects = $paginator->getCollection(); // the transformer, at this point, needs to collect information that ALL items in the collection // require, like meta data and stuff like that, and save it for later. @@ -94,4 +105,59 @@ class Controller extends BaseController return $manager->createData($resource)->toArray(); } + /** + * TODO duplicate from V1 controller + * Method to grab all parameters from the URL. + * + * @return ParameterBag + */ + private function getParameters(): ParameterBag + { + $bag = new ParameterBag; + try { + $page = (int) request()->get('page'); + } catch (ContainerExceptionInterface|NotFoundExceptionInterface $e) { + $page = 1; + } + + $integers = ['limit']; + $dates = ['start', 'end', 'date']; + + if ($page < 1) { + $page = 1; + } + if ($page > (2 ^ 16)) { + $page = (2 ^ 16); + } + $bag->set('page', $page); + + // some date fields: + foreach ($dates as $field) { + $date = request()->query->get($field); + $obj = null; + if (null !== $date) { + try { + $obj = Carbon::parse($date); + } catch (InvalidDateException|InvalidFormatException $e) { + // don't care + Log::warning(sprintf('Ignored invalid date "%s" in API v2 controller parameter check: %s', $date, $e->getMessage())); + } + } + $bag->set($field, $obj); + } + + // integer fields: + foreach ($integers as $integer) { + $value = request()->query->get($integer); + if (null !== $value) { + $bag->set($integer, (int) $value); + } + } + + // sort fields: + // return $this->getSortParameters($bag); + + return $bag; + } + } diff --git a/app/Api/V2/Controllers/Model/Account/ShowController.php b/app/Api/V2/Controllers/Model/Account/ShowController.php index 8f88817429..dac2bf123c 100644 --- a/app/Api/V2/Controllers/Model/Account/ShowController.php +++ b/app/Api/V2/Controllers/Model/Account/ShowController.php @@ -26,6 +26,7 @@ use FireflyIII\Api\V2\Controllers\Controller; use FireflyIII\Models\Account; use FireflyIII\Transformers\V2\AccountTransformer; use Illuminate\Http\JsonResponse; +use Illuminate\Http\Request; /** * Class ShowController @@ -37,9 +38,11 @@ class ShowController extends Controller * @param Account $account * @return JsonResponse */ - public function show(Account $account): JsonResponse + public function show(Request $request, Account $account): JsonResponse { $transformer = new AccountTransformer; + $transformer->setParameters($this->parameters); + return response() ->api($this->jsonApiObject('accounts', $account, $transformer)) ->header('Content-Type', self::CONTENT_TYPE); diff --git a/app/Support/Amount.php b/app/Support/Amount.php index 4ef63ea5bc..b6a7bb9485 100644 --- a/app/Support/Amount.php +++ b/app/Support/Amount.php @@ -139,7 +139,6 @@ class Amount /** * @return TransactionCurrency * @throws FireflyException - * @throws JsonException */ public function getDefaultCurrency(): TransactionCurrency { diff --git a/app/Support/Steam.php b/app/Support/Steam.php index 1f2ebc9777..d9ac3009f3 100644 --- a/app/Support/Steam.php +++ b/app/Support/Steam.php @@ -206,7 +206,6 @@ class Steam * * @return string * @throws FireflyException - * @throws JsonException */ public function balance(Account $account, Carbon $date, ?TransactionCurrency $currency = null): string { @@ -255,7 +254,6 @@ class Steam * @param Carbon $date * * @return array - * @throws JsonException */ public function balancesByAccounts(Collection $accounts, Carbon $date): array { diff --git a/app/Transformers/AccountTransformer.php b/app/Transformers/AccountTransformer.php index 19649aaedb..61b743fc13 100644 --- a/app/Transformers/AccountTransformer.php +++ b/app/Transformers/AccountTransformer.php @@ -28,6 +28,7 @@ use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\Account; use FireflyIII\Repositories\Account\AccountRepositoryInterface; use JsonException; +use Symfony\Component\HttpFoundation\ParameterBag; /** * Class AccountTransformer @@ -44,6 +45,7 @@ class AccountTransformer extends AbstractTransformer */ public function __construct() { + $this->parameters = new ParameterBag; $this->repository = app(AccountRepositoryInterface::class); } @@ -154,6 +156,7 @@ class AccountTransformer extends AbstractTransformer } /** + * TODO duplicated in the V2 transformer. * @return Carbon */ private function getDate(): Carbon diff --git a/app/Transformers/V2/AbstractTransformer.php b/app/Transformers/V2/AbstractTransformer.php index b69a644141..1f927b5cab 100644 --- a/app/Transformers/V2/AbstractTransformer.php +++ b/app/Transformers/V2/AbstractTransformer.php @@ -24,16 +24,35 @@ namespace FireflyIII\Transformers\V2; use Illuminate\Support\Collection; use League\Fractal\TransformerAbstract; +use Symfony\Component\HttpFoundation\ParameterBag; /** * Class AbstractTransformer */ abstract class AbstractTransformer extends TransformerAbstract { + protected ParameterBag $parameters; /** * @param Collection $objects * @return void */ abstract public function collectMetaData(Collection $objects): void; + + + /** + * @return ParameterBag + */ + final public function getParameters(): ParameterBag + { + return $this->parameters; + } + + /** + * @param ParameterBag $parameters + */ + final public function setParameters(ParameterBag $parameters): void + { + $this->parameters = $parameters; + } } diff --git a/app/Transformers/V2/AccountTransformer.php b/app/Transformers/V2/AccountTransformer.php index 39423fc264..e67948daed 100644 --- a/app/Transformers/V2/AccountTransformer.php +++ b/app/Transformers/V2/AccountTransformer.php @@ -22,7 +22,12 @@ declare(strict_types=1); namespace FireflyIII\Transformers\V2; +use Carbon\Carbon; +use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\Account; +use FireflyIII\Models\AccountMeta; +use FireflyIII\Models\TransactionCurrency; +use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use Illuminate\Support\Collection; /** @@ -30,6 +35,11 @@ use Illuminate\Support\Collection; */ class AccountTransformer extends AbstractTransformer { + private array $currencies; + private array $accountMeta; + private ?TransactionCurrency $currency; + private array $balances; + /** * Transform the account. * @@ -39,8 +49,15 @@ class AccountTransformer extends AbstractTransformer */ public function transform(Account $account): array { - $fullType = $account->accountType->type; - $accountType = (string) config(sprintf('firefly.shortNamesByFullName.%s', $fullType)); + //$fullType = $account->accountType->type; + //$accountType = (string) config(sprintf('firefly.shortNamesByFullName.%s', $fullType)); + $id = (int) $account->id; + + // no currency? use default + $currency = $this->currency; + if (0 !== (int) $this->accountMeta[$id]['currency_id']) { + $currency = $this->currencies[(int) $this->accountMeta[$id]['currency_id']]; + } return [ 'id' => (string) $account->id, @@ -49,32 +66,32 @@ class AccountTransformer extends AbstractTransformer 'active' => $account->active, //'order' => $order, 'name' => $account->name, - 'type' => strtolower($accountType), -// 'account_role' => $accountRole, -// 'currency_id' => $currencyId, -// 'currency_code' => $currencyCode, -// 'currency_symbol' => $currencySymbol, -// 'currency_decimal_places' => $decimalPlaces, -// 'current_balance' => number_format((float) app('steam')->balance($account, $date), $decimalPlaces, '.', ''), -// 'current_balance_date' => $date->toAtomString(), -// 'notes' => $this->repository->getNoteText($account), -// 'monthly_payment_date' => $monthlyPaymentDate, -// 'credit_card_type' => $creditCardType, -// 'account_number' => $this->repository->getMetaValue($account, 'account_number'), + // 'type' => strtolower($accountType), + // 'account_role' => $accountRole, + 'currency_id' => $currency->id, + 'currency_code' => $currency->code, + 'currency_symbol' => $currency->symbol, + 'currency_decimal_places' => $currency->decimal_places, + 'current_balance' => $this->balances[$id] ?? null, + 'current_balance_date' => $this->getDate(), + // 'notes' => $this->repository->getNoteText($account), + // 'monthly_payment_date' => $monthlyPaymentDate, + // 'credit_card_type' => $creditCardType, + // 'account_number' => $this->repository->getMetaValue($account, 'account_number'), 'iban' => '' === $account->iban ? null : $account->iban, -// 'bic' => $this->repository->getMetaValue($account, 'BIC'), -// 'virtual_balance' => number_format((float) $account->virtual_balance, $decimalPlaces, '.', ''), -// 'opening_balance' => $openingBalance, -// 'opening_balance_date' => $openingBalanceDate, -// 'liability_type' => $liabilityType, -// 'liability_direction' => $liabilityDirection, -// 'interest' => $interest, -// 'interest_period' => $interestPeriod, -// 'current_debt' => $this->repository->getMetaValue($account, 'current_debt'), -// 'include_net_worth' => $includeNetWorth, -// 'longitude' => $longitude, -// 'latitude' => $latitude, -// 'zoom_level' => $zoomLevel, + // 'bic' => $this->repository->getMetaValue($account, 'BIC'), + // 'virtual_balance' => number_format((float) $account->virtual_balance, $decimalPlaces, '.', ''), + // 'opening_balance' => $openingBalance, + // 'opening_balance_date' => $openingBalanceDate, + // 'liability_type' => $liabilityType, + // 'liability_direction' => $liabilityDirection, + // 'interest' => $interest, + // 'interest_period' => $interestPeriod, + // 'current_debt' => $this->repository->getMetaValue($account, 'current_debt'), + // 'include_net_worth' => $includeNetWorth, + // 'longitude' => $longitude, + // 'latitude' => $latitude, + // 'zoom_level' => $zoomLevel, 'links' => [ [ 'rel' => 'self', @@ -84,11 +101,48 @@ class AccountTransformer extends AbstractTransformer ]; } + /** + * @return Carbon + */ + private function getDate(): Carbon + { + $date = today(config('app.timezone')); + if (null !== $this->parameters->get('date')) { + $date = $this->parameters->get('date'); + } + + return $date; + } + /** * @inheritDoc + * @throws FireflyException */ public function collectMetaData(Collection $objects): void { - // TODO: Implement collectMetaData() method. + $this->currency = null; + $this->currencies = []; + $this->accountMeta = []; + $this->balances = app('steam')->balancesByAccounts($objects, $this->getDate()); + $repository = app(CurrencyRepositoryInterface::class); + $this->currency = app('amount')->getDefaultCurrency(); + + // get currencies: + $accountIds = $objects->pluck('id')->toArray(); + $meta = AccountMeta + ::whereIn('account_id', $accountIds) + ->where('name', 'currency_id') + ->get(['account_meta.id', 'account_meta.account_id', 'account_meta.name', 'account_meta.data']); + $currencyIds = $meta->pluck('data')->toArray(); + + $currencies = $repository->getByIds($currencyIds); + foreach ($currencies as $currency) { + $id = (int) $currency->id; + $this->currencies[$id] = $currency; + } + foreach ($meta as $entry) { + $id = (int) $entry->account_id; + $this->accountMeta[$id][$entry->name] = $entry->data; + } } } diff --git a/frontend/package.json b/frontend/package.json index 4b72d311d8..e3bf318613 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@popperjs/core": "^2.11.2", - "@quasar/extras": "^1.14.2", + "@quasar/extras": "^1.14.3", "apexcharts": "^3.32.1", "axios": "^0.21.1", "axios-cache-adapter": "^2.7.3", diff --git a/frontend/src/components/dashboard/TransactionList.vue b/frontend/src/components/dashboard/TransactionList.vue index c3c7de7552..91c5db4ebc 100644 --- a/frontend/src/components/dashboard/TransactionList.vue +++ b/frontend/src/components/dashboard/TransactionList.vue @@ -23,7 +23,11 @@ - {{ accountName }} (balance) + {{ accountName }} + + ({{ formatAmount(accountCurrencyCode,accountBalance) }}) + + @@ -110,6 +114,8 @@ export default { store: null, accountName: '', transactions: [], + accountCurrencyCode: '', + accountBalance: 0.0 } }, mounted() { @@ -135,7 +141,10 @@ export default { (new Get).get(this.accountId).then((response) => this.parseAccount(response.data)); }, parseAccount: function (data) { + console.log(data.data.attributes); this.accountName = data.data.attributes.name; + this.accountBalance = data.data.attributes.current_balance; + this.accountCurrencyCode = data.data.attributes.currency_code; }, getTransactions: function () { if (null !== this.store.getRange.start && null !== this.store.getRange.end) { diff --git a/frontend/yarn.lock b/frontend/yarn.lock index e9cba1f3b3..639138f149 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -1252,10 +1252,10 @@ core-js "^3.6.5" core-js-compat "^3.6.5" -"@quasar/extras@^1.14.2": - version "1.14.2" - resolved "https://registry.yarnpkg.com/@quasar/extras/-/extras-1.14.2.tgz#a5382ec83ddf967f8bc17d0dbe6ef88ddb31b796" - integrity sha512-F9T1aIhRIiuJeuxPCu2CBlPj5js6mBZWQOAHHyVlreNa5qhVEHhr/9GfljG6RTnjvTNOjJraTl0hi8g0IuUfLw== +"@quasar/extras@^1.14.3": + version "1.14.3" + resolved "https://registry.yarnpkg.com/@quasar/extras/-/extras-1.14.3.tgz#2a4d7a2f773a789ca43e3a02d5b797c9d2888884" + integrity sha512-OHyR/pfW0R8E5DvnsV1wg9ISnLL/yXHyOMZsqPY3gUtmfdF2634x2osdVg4YpBYW29vIQeV5feGWGIx8nuprdA== "@quasar/fastclick@1.1.5": version "1.1.5"