mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-29 18:20:01 +00:00
First code for new balance chart
This commit is contained in:
218
app/Api/V2/Controllers/Chart/BalanceController.php
Normal file
218
app/Api/V2/Controllers/Chart/BalanceController.php
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* BalanceController.php
|
||||||
|
* Copyright (c) 2023 james@firefly-iii.org
|
||||||
|
*
|
||||||
|
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace FireflyIII\Api\V2\Controllers\Chart;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Api\V2\Controllers\Controller;
|
||||||
|
use FireflyIII\Api\V2\Request\Chart\BalanceChartRequest;
|
||||||
|
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||||
|
use FireflyIII\Models\TransactionCurrency;
|
||||||
|
use FireflyIII\Models\TransactionType;
|
||||||
|
use FireflyIII\Repositories\Administration\Account\AccountRepositoryInterface;
|
||||||
|
use FireflyIII\Support\Http\Api\ConvertsExchangeRates;
|
||||||
|
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class BalanceController
|
||||||
|
*/
|
||||||
|
class BalanceController extends Controller
|
||||||
|
{
|
||||||
|
use ConvertsExchangeRates;
|
||||||
|
|
||||||
|
private AccountRepositoryInterface $repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
$this->middleware(
|
||||||
|
function ($request, $next) {
|
||||||
|
$this->repository = app(AccountRepositoryInterface::class);
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The code is practically a duplicate of ReportController::operations.
|
||||||
|
*
|
||||||
|
* Currency is up to the account/transactions in question, but conversion to the default
|
||||||
|
* currency is possible.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param BalanceChartRequest $request
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function balance(BalanceChartRequest $request): string
|
||||||
|
{
|
||||||
|
$params = $request->getAll();
|
||||||
|
/** @var Carbon $start */
|
||||||
|
$start = $params['start'];
|
||||||
|
/** @var Carbon $end */
|
||||||
|
$end = $params['end'];
|
||||||
|
/** @var Collection $accounts */
|
||||||
|
$accounts = $params['accounts'];
|
||||||
|
$preferredRange = $params['period'];
|
||||||
|
$convert = $params['convert'];
|
||||||
|
|
||||||
|
// set some formats, based on input parameters.
|
||||||
|
$format = app('navigation')->preferredCarbonFormatByPeriod($preferredRange);
|
||||||
|
$titleFormat = app('navigation')->preferredCarbonLocalizedFormatByPeriod($preferredRange);
|
||||||
|
|
||||||
|
// prepare for currency conversion and data collection:
|
||||||
|
$ids = $accounts->pluck('id')->toArray();
|
||||||
|
/** @var TransactionCurrency $default */
|
||||||
|
$default = app('amount')->getDefaultCurrency();
|
||||||
|
$converter = new ExchangeRateConverter();
|
||||||
|
$currencies = [(int)$default->id => $default,]; // currency cache
|
||||||
|
$data = [];
|
||||||
|
$chartData = [];
|
||||||
|
|
||||||
|
// get journals for entire period:
|
||||||
|
/** @var GroupCollectorInterface $collector */
|
||||||
|
$collector = app(GroupCollectorInterface::class);
|
||||||
|
$collector->setRange($start, $end)->withAccountInformation();
|
||||||
|
$collector->setXorAccounts($accounts);
|
||||||
|
$collector->setTypes([TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::RECONCILIATION, TransactionType::TRANSFER]);
|
||||||
|
$journals = $collector->getExtractedJournals();
|
||||||
|
|
||||||
|
// set array for default currency (even if unused later on)
|
||||||
|
$defaultCurrencyId = (int)$default->id;
|
||||||
|
$data[$defaultCurrencyId] = [
|
||||||
|
'currency_id' => $defaultCurrencyId,
|
||||||
|
'currency_symbol' => $default->symbol,
|
||||||
|
'currency_code' => $default->code,
|
||||||
|
'currency_name' => $default->name,
|
||||||
|
'currency_decimal_places' => (int)$default->decimal_places,
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
// loop. group by currency and by period.
|
||||||
|
/** @var array $journal */
|
||||||
|
foreach ($journals as $journal) {
|
||||||
|
// format the date according to the period
|
||||||
|
$period = $journal['date']->format($format);
|
||||||
|
|
||||||
|
// collect (and cache) currency information for this journal.
|
||||||
|
$currencyId = (int)$journal['currency_id'];
|
||||||
|
$currency = $currencies[$currencyId] ?? TransactionCurrency::find($currencyId);
|
||||||
|
$currencies[$currencyId] = $currency; // may just re-assign itself, don't mind.
|
||||||
|
|
||||||
|
// set the array with monetary info, if it does not exist.
|
||||||
|
$data[$currencyId] = $data[$currencyId] ?? [
|
||||||
|
'currency_id' => $currencyId,
|
||||||
|
'currency_symbol' => $currencySymbol,
|
||||||
|
'currency_code' => $currencyCode,
|
||||||
|
'currency_name' => $currencyName,
|
||||||
|
'currency_decimal_places' => $currencyDecimalPlaces,
|
||||||
|
];
|
||||||
|
|
||||||
|
// set the array with spent/earned in this $period, if it does not exist.
|
||||||
|
$data[$currencyId][$period] = $data[$currencyId][$period] ?? [
|
||||||
|
'period' => $period,
|
||||||
|
'spent' => '0',
|
||||||
|
'earned' => '0',
|
||||||
|
'spent_converted' => '0',
|
||||||
|
'earned_converted' => '0',
|
||||||
|
];
|
||||||
|
// is this amount in- our outgoing?
|
||||||
|
$key = 'spent';
|
||||||
|
$amount = app('steam')->negative($journal['amount']);
|
||||||
|
$amountConverted = $amount;
|
||||||
|
// deposit = incoming
|
||||||
|
// transfer or reconcile or opening balance, and these accounts are the destination.
|
||||||
|
if (
|
||||||
|
TransactionType::DEPOSIT === $journal['transaction_type_type']
|
||||||
|
||
|
||||||
|
|
||||||
|
(
|
||||||
|
(
|
||||||
|
TransactionType::TRANSFER === $journal['transaction_type_type']
|
||||||
|
|| TransactionType::RECONCILIATION === $journal['transaction_type_type']
|
||||||
|
|| TransactionType::OPENING_BALANCE === $journal['transaction_type_type']
|
||||||
|
)
|
||||||
|
&& in_array($journal['destination_account_id'], $ids, true)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
$key = 'earned';
|
||||||
|
$amount = app('steam')->positive($journal['amount']);
|
||||||
|
$amountConverted = $amount;
|
||||||
|
}
|
||||||
|
// if configured convert the amount, convert the amount to $default
|
||||||
|
if ($convert) {
|
||||||
|
$rate = $converter->getCurrencyRate($currency, $default, $journal['date']);
|
||||||
|
$amountConverted = bcmul($amount, $rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data[$currencyId][$period][$key] = bcadd($data[$currencyId][$period][$key], $amount);
|
||||||
|
$convertedKey = sprintf('%s_converted', $key);
|
||||||
|
$data[$currencyId][$period][$convertedKey] = bcadd($data[$currencyId][$period][$convertedKey], $amountConverted);
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop this data, make chart bars for each currency:
|
||||||
|
/** @var array $currency */
|
||||||
|
foreach ($data as $currency) {
|
||||||
|
$income = [
|
||||||
|
'label' => 'earned',
|
||||||
|
'currency_id' => $currency['currency_id'],
|
||||||
|
'currency_symbol' => $currency['currency_symbol'],
|
||||||
|
'currency_code' => $currency['currency_code'],
|
||||||
|
'entries' => [],
|
||||||
|
'converted_entries' => [],
|
||||||
|
];
|
||||||
|
$expense = [
|
||||||
|
'label' => 'spent',
|
||||||
|
'currency_id' => $currency['currency_id'],
|
||||||
|
'currency_symbol' => $currency['currency_symbol'],
|
||||||
|
'currency_code' => $currency['currency_code'],
|
||||||
|
'entries' => [],
|
||||||
|
'converted_entries' => [],
|
||||||
|
|
||||||
|
];
|
||||||
|
// loop all possible periods between $start and $end, and add them to the correct dataset.
|
||||||
|
$currentStart = clone $start;
|
||||||
|
while ($currentStart <= $end) {
|
||||||
|
$key = $currentStart->format($format);
|
||||||
|
$title = $currentStart->isoFormat($titleFormat);
|
||||||
|
$income['entries'][$title] = app('steam')->bcround(($currency[$key]['earned'] ?? '0'), $currency['currency_decimal_places']);
|
||||||
|
$expense['entries'][$title] = app('steam')->bcround(($currency[$key]['spent'] ?? '0'), $currency['currency_decimal_places']);
|
||||||
|
$currentStart = app('navigation')->addPeriod($currentStart, $preferredRange, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
$chartData[] = $income;
|
||||||
|
$chartData[] = $expense;
|
||||||
|
}
|
||||||
|
var_dump($chartData);
|
||||||
|
exit;
|
||||||
|
|
||||||
|
//$data = $this->generator->multiSet($chartData);
|
||||||
|
|
||||||
|
return response()->json($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
87
app/Api/V2/Request/Chart/BalanceChartRequest.php
Normal file
87
app/Api/V2/Request/Chart/BalanceChartRequest.php
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* BalanceChartRequest.php
|
||||||
|
* Copyright (c) 2023 james@firefly-iii.org
|
||||||
|
*
|
||||||
|
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace FireflyIII\Api\V2\Request\Chart;
|
||||||
|
|
||||||
|
use FireflyIII\Support\Request\ChecksLogin;
|
||||||
|
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Validator;
|
||||||
|
|
||||||
|
class BalanceChartRequest extends FormRequest
|
||||||
|
{
|
||||||
|
use ConvertsDataTypes;
|
||||||
|
use ChecksLogin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all data from the request.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAll(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'start' => $this->getCarbonDate('start'),
|
||||||
|
'end' => $this->getCarbonDate('end'),
|
||||||
|
'accounts' => $this->getAccountList(),
|
||||||
|
'convert' => $this->boolean('convert'),
|
||||||
|
'period' => $this->string('period'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The rules that the incoming request must be matched against.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'start' => 'required|date|after:1900-01-01|before:2099-12-31',
|
||||||
|
'end' => 'required|date|after_or_equal:start|before:2099-12-31|after:1900-01-01',
|
||||||
|
'convert' => 'nullable|between:0,1|numeric',
|
||||||
|
'accounts.*' => 'required|exists:accounts,id',
|
||||||
|
'period' => sprintf('required|in:%s', join(',', config('firefly.valid_view_ranges'))),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Validator $validator
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function withValidator(Validator $validator): void
|
||||||
|
{
|
||||||
|
$validator->after(
|
||||||
|
function (Validator $validator) {
|
||||||
|
// validate transaction query data.
|
||||||
|
$data = $validator->getData();
|
||||||
|
if (!array_key_exists('accounts', $data)) {
|
||||||
|
$validator->errors()->add('accounts', trans('validation.filled', ['attribute' => 'accounts']));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!is_array($data['accounts'])) {
|
||||||
|
$validator->errors()->add('accounts', trans('validation.filled', ['attribute' => 'accounts']));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -39,82 +39,6 @@ class AccountRepository implements AccountRepositoryInterface
|
|||||||
{
|
{
|
||||||
use AdministrationTrait;
|
use AdministrationTrait;
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
public function searchAccount(string $query, array $types, int $limit): Collection
|
|
||||||
{
|
|
||||||
// search by group, not by user
|
|
||||||
$dbQuery = $this->userGroup->accounts()
|
|
||||||
->where('active', true)
|
|
||||||
->orderBy('accounts.order', 'ASC')
|
|
||||||
->orderBy('accounts.account_type_id', 'ASC')
|
|
||||||
->orderBy('accounts.name', 'ASC')
|
|
||||||
->with(['accountType']);
|
|
||||||
if ('' !== $query) {
|
|
||||||
// split query on spaces just in case:
|
|
||||||
$parts = explode(' ', $query);
|
|
||||||
foreach ($parts as $part) {
|
|
||||||
$search = sprintf('%%%s%%', $part);
|
|
||||||
$dbQuery->where('name', 'LIKE', $search);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (0 !== count($types)) {
|
|
||||||
$dbQuery->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
|
|
||||||
$dbQuery->whereIn('account_types.type', $types);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $dbQuery->take($limit)->get(['accounts.*']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
public function getAccountsByType(array $types, ?array $sort = []): Collection
|
|
||||||
{
|
|
||||||
$res = array_intersect([AccountType::ASSET, AccountType::MORTGAGE, AccountType::LOAN, AccountType::DEBT], $types);
|
|
||||||
$query = $this->userGroup->accounts();
|
|
||||||
if (0 !== count($types)) {
|
|
||||||
$query->accountTypeIn($types);
|
|
||||||
}
|
|
||||||
|
|
||||||
// add sort parameters. At this point they're filtered to allowed fields to sort by:
|
|
||||||
if (0 !== count($sort)) {
|
|
||||||
foreach ($sort as $param) {
|
|
||||||
$query->orderBy($param[0], $param[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 === count($sort)) {
|
|
||||||
if (0 !== count($res)) {
|
|
||||||
$query->orderBy('accounts.order', 'ASC');
|
|
||||||
}
|
|
||||||
$query->orderBy('accounts.active', 'DESC');
|
|
||||||
$query->orderBy('accounts.name', 'ASC');
|
|
||||||
}
|
|
||||||
return $query->get(['accounts.*']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $accountIds
|
|
||||||
*
|
|
||||||
* @return Collection
|
|
||||||
*/
|
|
||||||
public function getAccountsById(array $accountIds): Collection
|
|
||||||
{
|
|
||||||
$query = $this->userGroup->accounts();
|
|
||||||
|
|
||||||
if (0 !== count($accountIds)) {
|
|
||||||
$query->whereIn('accounts.id', $accountIds);
|
|
||||||
}
|
|
||||||
$query->orderBy('accounts.order', 'ASC');
|
|
||||||
$query->orderBy('accounts.active', 'DESC');
|
|
||||||
$query->orderBy('accounts.name', 'ASC');
|
|
||||||
|
|
||||||
return $query->get(['accounts.*']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Account $account
|
* @param Account $account
|
||||||
*
|
*
|
||||||
@@ -141,7 +65,7 @@ class AccountRepository implements AccountRepositoryInterface
|
|||||||
* Return meta value for account. Null if not found.
|
* Return meta value for account. Null if not found.
|
||||||
*
|
*
|
||||||
* @param Account $account
|
* @param Account $account
|
||||||
* @param string $field
|
* @param string $field
|
||||||
*
|
*
|
||||||
* @return null|string
|
* @return null|string
|
||||||
*/
|
*/
|
||||||
@@ -161,4 +85,93 @@ class AccountRepository implements AccountRepositoryInterface
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $accountId
|
||||||
|
*
|
||||||
|
* @return Account|null
|
||||||
|
*/
|
||||||
|
public function find(int $accountId): ?Account
|
||||||
|
{
|
||||||
|
$account = $this->user->accounts()->find($accountId);
|
||||||
|
if (null === $account) {
|
||||||
|
$account = $this->userGroup->accounts()->find($accountId);
|
||||||
|
}
|
||||||
|
return $account;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $accountIds
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getAccountsById(array $accountIds): Collection
|
||||||
|
{
|
||||||
|
$query = $this->userGroup->accounts();
|
||||||
|
|
||||||
|
if (0 !== count($accountIds)) {
|
||||||
|
$query->whereIn('accounts.id', $accountIds);
|
||||||
|
}
|
||||||
|
$query->orderBy('accounts.order', 'ASC');
|
||||||
|
$query->orderBy('accounts.active', 'DESC');
|
||||||
|
$query->orderBy('accounts.name', 'ASC');
|
||||||
|
|
||||||
|
return $query->get(['accounts.*']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getAccountsByType(array $types, ?array $sort = []): Collection
|
||||||
|
{
|
||||||
|
$res = array_intersect([AccountType::ASSET, AccountType::MORTGAGE, AccountType::LOAN, AccountType::DEBT], $types);
|
||||||
|
$query = $this->userGroup->accounts();
|
||||||
|
if (0 !== count($types)) {
|
||||||
|
$query->accountTypeIn($types);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add sort parameters. At this point they're filtered to allowed fields to sort by:
|
||||||
|
if (0 !== count($sort)) {
|
||||||
|
foreach ($sort as $param) {
|
||||||
|
$query->orderBy($param[0], $param[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 === count($sort)) {
|
||||||
|
if (0 !== count($res)) {
|
||||||
|
$query->orderBy('accounts.order', 'ASC');
|
||||||
|
}
|
||||||
|
$query->orderBy('accounts.active', 'DESC');
|
||||||
|
$query->orderBy('accounts.name', 'ASC');
|
||||||
|
}
|
||||||
|
return $query->get(['accounts.*']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function searchAccount(string $query, array $types, int $limit): Collection
|
||||||
|
{
|
||||||
|
// search by group, not by user
|
||||||
|
$dbQuery = $this->userGroup->accounts()
|
||||||
|
->where('active', true)
|
||||||
|
->orderBy('accounts.order', 'ASC')
|
||||||
|
->orderBy('accounts.account_type_id', 'ASC')
|
||||||
|
->orderBy('accounts.name', 'ASC')
|
||||||
|
->with(['accountType']);
|
||||||
|
if ('' !== $query) {
|
||||||
|
// split query on spaces just in case:
|
||||||
|
$parts = explode(' ', $query);
|
||||||
|
foreach ($parts as $part) {
|
||||||
|
$search = sprintf('%%%s%%', $part);
|
||||||
|
$dbQuery->where('name', 'LIKE', $search);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (0 !== count($types)) {
|
||||||
|
$dbQuery->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
|
||||||
|
$dbQuery->whereIn('account_types.type', $types);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $dbQuery->take($limit)->get(['accounts.*']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -35,28 +35,11 @@ use Illuminate\Support\Collection;
|
|||||||
interface AccountRepositoryInterface
|
interface AccountRepositoryInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param string $query
|
* @param int $accountId
|
||||||
* @param array $types
|
|
||||||
* @param int $limit
|
|
||||||
*
|
*
|
||||||
* @return Collection
|
* @return Account|null
|
||||||
*/
|
*/
|
||||||
public function searchAccount(string $query, array $types, int $limit): Collection;
|
public function find(int $accountId): ?Account;
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $types
|
|
||||||
* @param array|null $sort
|
|
||||||
*
|
|
||||||
* @return Collection
|
|
||||||
*/
|
|
||||||
public function getAccountsByType(array $types, ?array $sort = []): Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $accountIds
|
|
||||||
*
|
|
||||||
* @return Collection
|
|
||||||
*/
|
|
||||||
public function getAccountsById(array $accountIds): Collection;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Account $account
|
* @param Account $account
|
||||||
@@ -65,13 +48,38 @@ interface AccountRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function getAccountCurrency(Account $account): ?TransactionCurrency;
|
public function getAccountCurrency(Account $account): ?TransactionCurrency;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $accountIds
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getAccountsById(array $accountIds): Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $types
|
||||||
|
* @param array|null $sort
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getAccountsByType(array $types, ?array $sort = []): Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return meta value for account. Null if not found.
|
* Return meta value for account. Null if not found.
|
||||||
*
|
*
|
||||||
* @param Account $account
|
* @param Account $account
|
||||||
* @param string $field
|
* @param string $field
|
||||||
*
|
*
|
||||||
* @return null|string
|
* @return null|string
|
||||||
*/
|
*/
|
||||||
public function getMetaValue(Account $account, string $field): ?string;
|
public function getMetaValue(Account $account, string $field): ?string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $query
|
||||||
|
* @param array $types
|
||||||
|
* @param int $limit
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function searchAccount(string $query, array $types, int $limit): Collection;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -89,10 +89,10 @@ class Navigation
|
|||||||
|
|
||||||
if (!array_key_exists($repeatFreq, $functionMap)) {
|
if (!array_key_exists($repeatFreq, $functionMap)) {
|
||||||
Log::error(sprintf(
|
Log::error(sprintf(
|
||||||
'The periodicity %s is unknown. Choose one of available periodicity: %s',
|
'The periodicity %s is unknown. Choose one of available periodicity: %s',
|
||||||
$repeatFreq,
|
$repeatFreq,
|
||||||
join(', ', array_keys($functionMap))
|
join(', ', array_keys($functionMap))
|
||||||
));
|
));
|
||||||
return $theDate;
|
return $theDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -515,6 +515,25 @@ class Navigation
|
|||||||
return $date->format('Y-m-d');
|
return $date->format('Y-m-d');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as preferredCarbonFormat but by string
|
||||||
|
*
|
||||||
|
* @param string $period
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function preferredCarbonFormatByPeriod(string $period): string
|
||||||
|
{
|
||||||
|
return match ($period) {
|
||||||
|
default => 'Y-m-d',
|
||||||
|
//'1D' => 'Y-m-d',
|
||||||
|
'1W' => '\WW,Y',
|
||||||
|
'1M' => 'Y-m',
|
||||||
|
'3M', '6M' => '\QQ,Y',
|
||||||
|
'1Y' => 'Y',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the date difference between start and end is less than a month, method returns trans(config.month_and_day).
|
* If the date difference between start and end is less than a month, method returns trans(config.month_and_day).
|
||||||
* If the difference is less than a year, method returns "config.month". If the date difference is larger, method
|
* If the difference is less than a year, method returns "config.month". If the date difference is larger, method
|
||||||
@@ -540,6 +559,25 @@ class Navigation
|
|||||||
return $format;
|
return $format;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as preferredCarbonLocalizedFormat but based on the period.
|
||||||
|
*
|
||||||
|
* @param string $period
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function preferredCarbonLocalizedFormatByPeriod(string $period): string
|
||||||
|
{
|
||||||
|
$locale = app('steam')->getLocale();
|
||||||
|
return match ($period) {
|
||||||
|
default => (string)trans('config.month_and_day_js', [], $locale),
|
||||||
|
'1W' => (string)trans('config.week_in_year_js', [], $locale),
|
||||||
|
'1M' => (string)trans('config.month_js', [], $locale),
|
||||||
|
'3M', '6M' => (string)trans('config.half_year_js', [], $locale),
|
||||||
|
'1Y' => (string)trans('config.year_js', [], $locale),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the date difference between start and end is less than a month, method returns "endOfDay". If the difference
|
* If the date difference between start and end is less than a month, method returns "endOfDay". If the difference
|
||||||
* is less than a year, method returns "endOfMonth". If the date difference is larger, method returns "endOfYear".
|
* is less than a year, method returns "endOfMonth". If the date difference is larger, method returns "endOfYear".
|
||||||
|
@@ -26,6 +26,8 @@ namespace FireflyIII\Support\Request;
|
|||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Carbon\Exceptions\InvalidDateException;
|
use Carbon\Exceptions\InvalidDateException;
|
||||||
use Carbon\Exceptions\InvalidFormatException;
|
use Carbon\Exceptions\InvalidFormatException;
|
||||||
|
use FireflyIII\Repositories\Administration\Account\AccountRepositoryInterface;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -153,6 +155,38 @@ trait ConvertsDataTypes
|
|||||||
return trim($string);
|
return trim($string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO duplicate, see SelectTransactionsRequest
|
||||||
|
*
|
||||||
|
* Validate list of accounts. This one is for V2 endpoints, so it searches for groups, not users.
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getAccountList(): Collection
|
||||||
|
{
|
||||||
|
// fixed
|
||||||
|
/** @var AccountRepositoryInterface $repository */
|
||||||
|
$repository = app(AccountRepositoryInterface::class);
|
||||||
|
|
||||||
|
// set administration ID
|
||||||
|
// group ID
|
||||||
|
$administrationId = auth()->user()->getAdministrationId();
|
||||||
|
$repository->setAdministrationId($administrationId);
|
||||||
|
|
||||||
|
$set = $this->get('accounts');
|
||||||
|
$collection = new Collection();
|
||||||
|
if (is_array($set)) {
|
||||||
|
foreach ($set as $accountId) {
|
||||||
|
$account = $repository->find((int)$accountId);
|
||||||
|
if (null !== $account) {
|
||||||
|
$collection->push($account);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $collection;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return string value with newlines.
|
* Return string value with newlines.
|
||||||
*
|
*
|
||||||
|
@@ -87,7 +87,8 @@ Route::group(
|
|||||||
'as' => 'api.v1.chart.',
|
'as' => 'api.v1.chart.',
|
||||||
],
|
],
|
||||||
static function () {
|
static function () {
|
||||||
Route::get('account/dashboard', ['uses' => 'AccountController@dashboard', 'as' => 'dashboard']);
|
Route::get('account/dashboard', ['uses' => 'AccountController@dashboard', 'as' => 'account.dashboard']);
|
||||||
|
Route::get('balance/balance', ['uses' => 'BalanceController@balance', 'as' => 'balance.balance']);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user