Clean up API and display of transactions.

This commit is contained in:
James Cole
2025-08-08 20:18:04 +02:00
parent 73512b0365
commit deca4fed56
14 changed files with 435 additions and 444 deletions

View File

@@ -0,0 +1,97 @@
<?php
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Chart;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Chart\ChartRequest;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Chart\ChartData;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Http\Api\AccountBalanceGrouped;
use FireflyIII\Support\Http\Api\CleansChartData;
use FireflyIII\Support\Http\Api\CollectsAccountsFromFilter;
use Illuminate\Http\JsonResponse;
/**
* Class BalanceController
*/
class BalanceController extends Controller
{
use CleansChartData;
use CollectsAccountsFromFilter;
private ChartData $chartData;
private GroupCollectorInterface $collector;
private AccountRepositoryInterface $repository;
// private TransactionCurrency $default;
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(AccountRepositoryInterface::class);
$this->collector = app(GroupCollectorInterface::class);
$userGroup = $this->validateUserGroup($request);
$this->repository->setUserGroup($userGroup);
$this->collector->setUserGroup($userGroup);
$this->chartData = new ChartData();
// $this->default = app('amount')->getPrimaryCurrency();
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.
*
* If the transaction being processed is already in native currency OR if the
* foreign amount is in the native currency, the amount will not be converted.
*
* @throws FireflyException
*/
public function balance(ChartRequest $request): JsonResponse
{
$queryParameters = $request->getParameters();
$accounts = $this->getAccountList($queryParameters);
// prepare for currency conversion and data collection:
/** @var TransactionCurrency $primary */
$primary = Amount::getPrimaryCurrency();
// get journals for entire period:
$this->collector->setRange($queryParameters['start'], $queryParameters['end'])
->withAccountInformation()
->setXorAccounts($accounts)
->setTypes([TransactionTypeEnum::WITHDRAWAL->value, TransactionTypeEnum::DEPOSIT->value, TransactionTypeEnum::RECONCILIATION->value, TransactionTypeEnum::TRANSFER->value]);
$journals = $this->collector->getExtractedJournals();
$object = new AccountBalanceGrouped();
$object->setPreferredRange($queryParameters['period']);
$object->setPrimary($primary);
$object->setAccounts($accounts);
$object->setJournals($journals);
$object->setStart($queryParameters['start']);
$object->setEnd($queryParameters['end']);
$object->groupByCurrencyAndPeriod();
$data = $object->convertToChartData();
foreach ($data as $entry) {
$this->chartData->add($entry);
}
return response()->json($this->chartData->render());
}
}

View File

@@ -40,6 +40,7 @@ use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\UserGroup; use FireflyIII\Models\UserGroup;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface; use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Preferences; use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Http\Api\ExchangeRateConverter; use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use Illuminate\Console\Command; use Illuminate\Console\Command;
@@ -72,6 +73,8 @@ class CorrectsPrimaryCurrencyAmounts extends Command
/** @var UserGroupRepositoryInterface $repository */ /** @var UserGroupRepositoryInterface $repository */
$repository = app(UserGroupRepositoryInterface::class); $repository = app(UserGroupRepositoryInterface::class);
Preferences::mark();
/** @var UserGroup $userGroup */ /** @var UserGroup $userGroup */
foreach ($repository->getAll() as $userGroup) { foreach ($repository->getAll() as $userGroup) {
$this->recalculateForGroup($userGroup); $this->recalculateForGroup($userGroup);
@@ -87,8 +90,7 @@ class CorrectsPrimaryCurrencyAmounts extends Command
$this->recalculateAccounts($userGroup); $this->recalculateAccounts($userGroup);
// do a check with the group's currency so we can skip some stuff. // do a check with the group's currency so we can skip some stuff.
Preferences::mark(); $currency = Amount::getPrimaryCurrencyByUserGroup($userGroup);
$currency = app('amount')->getPrimaryCurrencyByUserGroup($userGroup);
$this->recalculatePiggyBanks($userGroup, $currency); $this->recalculatePiggyBanks($userGroup, $currency);
$this->recalculateBudgets($userGroup, $currency); $this->recalculateBudgets($userGroup, $currency);

View File

@@ -35,6 +35,6 @@ class UserGroupChangedPrimaryCurrency extends Event
public function __construct(public UserGroup $userGroup) public function __construct(public UserGroup $userGroup)
{ {
Log::debug('User group changed default currency.'); Log::debug('User group changed primary currency.');
} }
} }

View File

@@ -73,6 +73,7 @@ class PreferencesEventHandler
$repository = app(PiggyBankRepositoryInterface::class); $repository = app(PiggyBankRepositoryInterface::class);
$repository->setUserGroup($userGroup); $repository->setUserGroup($userGroup);
$piggyBanks = $repository->getPiggyBanks(); $piggyBanks = $repository->getPiggyBanks();
Log::debug(sprintf('Resetting %d piggy bank(s).', $piggyBanks->count()));
/** @var PiggyBank $piggyBank */ /** @var PiggyBank $piggyBank */
foreach ($piggyBanks as $piggyBank) { foreach ($piggyBanks as $piggyBank) {
@@ -104,6 +105,8 @@ class PreferencesEventHandler
$repository->setUserGroup($userGroup); $repository->setUserGroup($userGroup);
$set = $repository->getBudgets(); $set = $repository->getBudgets();
Log::debug(sprintf('Resetting %d budget(s).', $set->count()));
/** @var Budget $budget */ /** @var Budget $budget */
foreach ($set as $budget) { foreach ($set as $budget) {
foreach ($budget->autoBudgets as $autoBudget) { foreach ($budget->autoBudgets as $autoBudget) {

View File

@@ -35,6 +35,7 @@ use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\CacheProperties; use FireflyIII\Support\CacheProperties;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Facades\Steam; use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Controllers\AugumentData; use FireflyIII\Support\Http\Controllers\AugumentData;
use FireflyIII\Support\Http\Controllers\ChartGeneration; use FireflyIII\Support\Http\Controllers\ChartGeneration;
@@ -42,7 +43,6 @@ use FireflyIII\Support\Http\Controllers\DateCalculation;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use function Safe\json_encode; use function Safe\json_encode;
/** /**
@@ -78,6 +78,7 @@ class AccountController extends Controller
/** /**
* Shows the balances for all the user's expense accounts (on the front page). * Shows the balances for all the user's expense accounts (on the front page).
* 2025-08-06 validated for multi (primary) currency
* *
* This chart is (multi) currency aware. * This chart is (multi) currency aware.
*/ */
@@ -114,8 +115,8 @@ class AccountController extends Controller
// grab all balances // grab all balances
Log::debug(sprintf('expenseAccounts: finalAccountsBalance("%s")', $start->format('Y-m-d H:i:s'))); Log::debug(sprintf('expenseAccounts: finalAccountsBalance("%s")', $start->format('Y-m-d H:i:s')));
Log::debug(sprintf('expenseAccounts: finalAccountsBalance("%s")', $end->format('Y-m-d H:i:s'))); Log::debug(sprintf('expenseAccounts: finalAccountsBalance("%s")', $end->format('Y-m-d H:i:s')));
$startBalances = Steam::finalAccountsBalance($accounts, $start); $startBalances = Steam::finalAccountsBalance($accounts, $start, $this->primaryCurrency, $this->convertToPrimary);
$endBalances = Steam::finalAccountsBalance($accounts, $end); $endBalances = Steam::finalAccountsBalance($accounts, $end, $this->primaryCurrency, $this->convertToPrimary);
// loop the accounts, then check for balance and currency info. // loop the accounts, then check for balance and currency info.
foreach ($accounts as $account) { foreach ($accounts as $account) {
@@ -157,7 +158,7 @@ class AccountController extends Controller
$tempData[] = [ $tempData[] = [
'name' => $accountNames[$account->id], 'name' => $accountNames[$account->id],
'difference' => $diff, 'difference' => $diff,
'diff_float' => (float) $diff, // intentional float 'diff_float' => (float)$diff, // intentional float
'currency_id' => $currencies[$searchCode]->id, 'currency_id' => $currencies[$searchCode]->id,
]; ];
} }
@@ -182,7 +183,7 @@ class AccountController extends Controller
foreach ($currencies as $currencyId => $currency) { foreach ($currencies as $currencyId => $currency) {
$dataSet $dataSet
= [ = [
'label' => (string) trans('firefly.spent'), 'label' => (string)trans('firefly.spent'),
'type' => 'bar', 'type' => 'bar',
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
@@ -195,7 +196,7 @@ class AccountController extends Controller
foreach ($tempData as $entry) { foreach ($tempData as $entry) {
$currencyId = $entry['currency_id']; $currencyId = $entry['currency_id'];
$name = $entry['name']; $name = $entry['name'];
$chartData[$currencyId]['entries'][$name] = (float) $entry['difference']; $chartData[$currencyId]['entries'][$name] = (float)$entry['difference'];
} }
$data = $this->generator->multiSet($chartData); $data = $this->generator->multiSet($chartData);
@@ -206,6 +207,7 @@ class AccountController extends Controller
/** /**
* Expenses per budget for all time, as shown on account overview. * Expenses per budget for all time, as shown on account overview.
*
*/ */
public function expenseBudgetAll(AccountRepositoryInterface $repository, Account $account): JsonResponse public function expenseBudgetAll(AccountRepositoryInterface $repository, Account $account): JsonResponse
{ {
@@ -223,6 +225,7 @@ class AccountController extends Controller
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty($account->id); $cache->addProperty($account->id);
$cache->addProperty($start); $cache->addProperty($start);
$cache->addProperty($this->convertToPrimary);
$cache->addProperty($end); $cache->addProperty($end);
$cache->addProperty('chart.account.expense-budget'); $cache->addProperty('chart.account.expense-budget');
if ($cache->has()) { if ($cache->has()) {
@@ -231,7 +234,9 @@ class AccountController extends Controller
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))->setRange($start, $end)->withBudgetInformation()->setTypes([TransactionTypeEnum::WITHDRAWAL->value]); $collector->setAccounts(new Collection([$account]))
->setRange($start, $end)
->withBudgetInformation()->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
$chartData = []; $chartData = [];
$result = []; $result = [];
@@ -239,19 +244,37 @@ class AccountController extends Controller
/** @var array $journal */ /** @var array $journal */
foreach ($journals as $journal) { foreach ($journals as $journal) {
$budgetId = (int) $journal['budget_id']; $budgetId = (int)$journal['budget_id'];
$key = sprintf('%d-%d', $budgetId, $journal['currency_id']); $key = sprintf('%d-%d', $budgetId, $journal['currency_id']);
$budgetIds[] = $budgetId; $budgetIds[] = $budgetId;
// currency info:
$currencyId = (int)$journal['currency_id'];
$currencyName = $journal['currency_name'];
$currencySymbol = $journal['currency_symbol'];
$currencyCode = $journal['currency_code'];
$currencyDecimalPlaces = $journal['currency_decimal_places'];
$field = 'amount';
if ($this->convertToPrimary && $this->primaryCurrency->id !== $currencyId) {
$field = 'pc_amount';
$currencyName = $this->primaryCurrency->name;
$currencySymbol = $this->primaryCurrency->symbol;
$currencyCode = $this->primaryCurrency->code;
$currencyDecimalPlaces = $this->primaryCurrency->decimal_places;
}
if (!array_key_exists($key, $result)) { if (!array_key_exists($key, $result)) {
$result[$key] = [ $result[$key] = [
'total' => '0', 'total' => '0',
'budget_id' => $budgetId, 'budget_id' => $budgetId,
'currency_name' => $journal['currency_name'], 'currency_name' => $currencyName,
'currency_symbol' => $journal['currency_symbol'], 'currency_symbol' => $currencySymbol,
'currency_code' => $journal['currency_code'], 'currency_code' => $currencyCode,
'currency_decimal_places' => $currencyDecimalPlaces,
]; ];
} }
$result[$key]['total'] = bcadd((string) $journal['amount'], $result[$key]['total']); $result[$key]['total'] = bcadd((string)$journal[$field], $result[$key]['total']);
} }
$names = $this->getBudgetNames($budgetIds); $names = $this->getBudgetNames($budgetIds);
@@ -259,7 +282,7 @@ class AccountController extends Controller
foreach ($result as $row) { foreach ($result as $row) {
$budgetId = $row['budget_id']; $budgetId = $row['budget_id'];
$name = $names[$budgetId]; $name = $names[$budgetId];
$label = (string) trans('firefly.name_in_currency', ['name' => $name, 'currency' => $row['currency_name']]); $label = (string)trans('firefly.name_in_currency', ['name' => $name, 'currency' => $row['currency_name']]);
$chartData[$label] = ['amount' => $row['total'], 'currency_symbol' => $row['currency_symbol'], 'currency_code' => $row['currency_code']]; $chartData[$label] = ['amount' => $row['total'], 'currency_symbol' => $row['currency_symbol'], 'currency_code' => $row['currency_code']];
} }
@@ -289,6 +312,7 @@ class AccountController extends Controller
$cache->addProperty($account->id); $cache->addProperty($account->id);
$cache->addProperty($start); $cache->addProperty($start);
$cache->addProperty($end); $cache->addProperty($end);
$cache->addProperty($this->convertToPrimary);
$cache->addProperty('chart.account.expense-category'); $cache->addProperty('chart.account.expense-category');
if ($cache->has()) { if ($cache->has()) {
return response()->json($cache->get()); return response()->json($cache->get());
@@ -305,22 +329,39 @@ class AccountController extends Controller
foreach ($journals as $journal) { foreach ($journals as $journal) {
$key = sprintf('%d-%d', $journal['category_id'], $journal['currency_id']); $key = sprintf('%d-%d', $journal['category_id'], $journal['currency_id']);
if (!array_key_exists($key, $result)) { if (!array_key_exists($key, $result)) {
// currency info:
$currencyId = (int)$journal['currency_id'];
$currencyName = $journal['currency_name'];
$currencySymbol = $journal['currency_symbol'];
$currencyCode = $journal['currency_code'];
$currencyDecimalPlaces = $journal['currency_decimal_places'];
$field = 'amount';
if ($this->convertToPrimary && $this->primaryCurrency->id !== $currencyId) {
$field = 'pc_amount';
$currencyName = $this->primaryCurrency->name;
$currencySymbol = $this->primaryCurrency->symbol;
$currencyCode = $this->primaryCurrency->code;
$currencyDecimalPlaces = $this->primaryCurrency->decimal_places;
}
$result[$key] = [ $result[$key] = [
'total' => '0', 'total' => '0',
'category_id' => (int) $journal['category_id'], 'category_id' => (int)$journal['category_id'],
'currency_name' => $journal['currency_name'], 'currency_name' => $currencyName,
'currency_symbol' => $journal['currency_symbol'], 'currency_code' => $currencyCode,
'currency_code' => $journal['currency_code'], 'currency_symbol' => $currencySymbol,
'currency_decimal_places' => $currencyDecimalPlaces,
]; ];
} }
$result[$key]['total'] = bcadd((string) $journal['amount'], $result[$key]['total']); $result[$key]['total'] = bcadd((string)$journal[$field], $result[$key]['total']);
} }
$names = $this->getCategoryNames(array_keys($result)); $names = $this->getCategoryNames(array_keys($result));
foreach ($result as $row) { foreach ($result as $row) {
$categoryId = $row['category_id']; $categoryId = $row['category_id'];
$name = $names[$categoryId] ?? '(unknown)'; $name = $names[$categoryId] ?? '(unknown)';
$label = (string) trans('firefly.name_in_currency', ['name' => $name, 'currency' => $row['currency_name']]); $label = (string)trans('firefly.name_in_currency', ['name' => $name, 'currency' => $row['currency_name']]);
$chartData[$label] = ['amount' => $row['total'], 'currency_symbol' => $row['currency_symbol'], 'currency_code' => $row['currency_code']]; $chartData[$label] = ['amount' => $row['total'], 'currency_symbol' => $row['currency_symbol'], 'currency_code' => $row['currency_code']];
} }
@@ -341,11 +382,11 @@ class AccountController extends Controller
$end = clone session('end', today(config('app.timezone'))->endOfMonth()); $end = clone session('end', today(config('app.timezone'))->endOfMonth());
$defaultSet = $repository->getAccountsByType([AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value])->pluck('id')->toArray(); $defaultSet = $repository->getAccountsByType([AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value])->pluck('id')->toArray();
// Log::debug('Default set is ', $defaultSet); // Log::debug('Default set is ', $defaultSet);
$frontpage = app('preferences')->get('frontpageAccounts', $defaultSet); $frontpage = Preferences::get('frontpageAccounts', $defaultSet);
$frontpageArray = !is_array($frontpage->data) ? [] : $frontpage->data; $frontpageArray = !is_array($frontpage->data) ? [] : $frontpage->data;
Log::debug('Frontpage preference set is ', $frontpageArray); Log::debug('Frontpage preference set is ', $frontpageArray);
if (0 === count($frontpageArray)) { if (0 === count($frontpageArray)) {
app('preferences')->set('frontpageAccounts', $defaultSet); Preferences::set('frontpageAccounts', $defaultSet);
Log::debug('frontpage set is empty!'); Log::debug('frontpage set is empty!');
} }
$accounts = $repository->getAccountsById($frontpageArray); $accounts = $repository->getAccountsById($frontpageArray);
@@ -402,14 +443,14 @@ class AccountController extends Controller
'currency_code' => $journal['currency_code'], 'currency_code' => $journal['currency_code'],
]; ];
} }
$result[$key]['total'] = bcadd((string) $journal['amount'], $result[$key]['total']); $result[$key]['total'] = bcadd((string)$journal['amount'], $result[$key]['total']);
} }
$names = $this->getCategoryNames(array_keys($result)); $names = $this->getCategoryNames(array_keys($result));
foreach ($result as $row) { foreach ($result as $row) {
$categoryId = $row['category_id']; $categoryId = $row['category_id'];
$name = $names[$categoryId] ?? '(unknown)'; $name = $names[$categoryId] ?? '(unknown)';
$label = (string) trans('firefly.name_in_currency', ['name' => $name, 'currency' => $row['currency_name']]); $label = (string)trans('firefly.name_in_currency', ['name' => $name, 'currency' => $row['currency_name']]);
$chartData[$label] = ['amount' => $row['total'], 'currency_symbol' => $row['currency_symbol'], 'currency_code' => $row['currency_code']]; $chartData[$label] = ['amount' => $row['total'], 'currency_symbol' => $row['currency_symbol'], 'currency_code' => $row['currency_code']];
} }
$data = $this->generator->multiCurrencyPieChart($chartData); $data = $this->generator->multiCurrencyPieChart($chartData);
@@ -450,7 +491,7 @@ class AccountController extends Controller
// This period depends on the size of the chart // This period depends on the size of the chart
$current = clone $start; $current = clone $start;
$current = app('navigation')->endOfX($current, $step, null); $current = app('navigation')->endOfX($current, $step, null);
$format = (string) trans('config.month_and_day_js', [], $locale); $format = (string)trans('config.month_and_day_js', [], $locale);
$accountCurrency = $this->accountRepository->getAccountCurrency($account); $accountCurrency = $this->accountRepository->getAccountCurrency($account);
$range = Steam::finalAccountBalanceInRange($account, $start, $end, $this->convertToPrimary); $range = Steam::finalAccountBalanceInRange($account, $start, $end, $this->convertToPrimary);
@@ -512,7 +553,7 @@ class AccountController extends Controller
foreach ($return as $key => $info) { foreach ($return as $key => $info) {
if ('balance' !== $key && 'pc_balance' !== $key) { if ('balance' !== $key && 'pc_balance' !== $key) {
// assume it's a currency: // assume it's a currency:
$setCurrency = $this->currencyRepository->findByCode((string) $key); $setCurrency = $this->currencyRepository->findByCode((string)$key);
$info['currency_symbol'] = $setCurrency->symbol; $info['currency_symbol'] = $setCurrency->symbol;
$info['currency_code'] = $setCurrency->code; $info['currency_code'] = $setCurrency->code;
$info['label'] = sprintf('%s (%s)', $account->name, $setCurrency->symbol); $info['label'] = sprintf('%s (%s)', $account->name, $setCurrency->symbol);
@@ -525,7 +566,7 @@ class AccountController extends Controller
if ('pc_balance' === $key) { if ('pc_balance' === $key) {
$info['currency_symbol'] = $this->primaryCurrency->symbol; $info['currency_symbol'] = $this->primaryCurrency->symbol;
$info['currency_code'] = $this->primaryCurrency->code; $info['currency_code'] = $this->primaryCurrency->code;
$info['label'] = sprintf('%s (%s) (%s)', $account->name, (string) trans('firefly.sum'), $this->primaryCurrency->symbol); $info['label'] = sprintf('%s (%s) (%s)', $account->name, (string)trans('firefly.sum'), $this->primaryCurrency->symbol);
} }
$chartData[] = $info; $chartData[] = $info;
} }
@@ -640,7 +681,7 @@ class AccountController extends Controller
$tempData[] = [ $tempData[] = [
'name' => $accountNames[$account->id], 'name' => $accountNames[$account->id],
'difference' => $diff, 'difference' => $diff,
'diff_float' => (float) $diff, // intentional float 'diff_float' => (float)$diff, // intentional float
'currency_id' => $currencies[$searchCode]->id, 'currency_id' => $currencies[$searchCode]->id,
]; ];
} }
@@ -667,7 +708,7 @@ class AccountController extends Controller
foreach ($currencies as $currencyId => $currency) { foreach ($currencies as $currencyId => $currency) {
$dataSet $dataSet
= [ = [
'label' => (string) trans('firefly.earned'), 'label' => (string)trans('firefly.earned'),
'type' => 'bar', 'type' => 'bar',
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_code' => $currency->code, 'currency_code' => $currency->code,

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers; namespace FireflyIII\Http\Controllers;
use FireflyIII\Support\Singleton\PreferencesSingleton;
use JsonException; use JsonException;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Enums\AccountTypeEnum; use FireflyIII\Enums\AccountTypeEnum;
@@ -269,7 +270,9 @@ class PreferencesController extends Controller
if ($convertToPrimary && !$this->convertToPrimary) { if ($convertToPrimary && !$this->convertToPrimary) {
// set to true! // set to true!
Log::debug('User sets convertToPrimary to true.'); Log::debug('User sets convertToPrimary to true.');
Preferences::set('convert_to_primary', $convertToPrimary); Preferences::set('convert_to_primary', true);
$singleton = PreferencesSingleton::getInstance();
$singleton->resetPreferences();
event(new UserGroupChangedPrimaryCurrency(auth()->user()->userGroup)); event(new UserGroupChangedPrimaryCurrency(auth()->user()->userGroup));
} }
Preferences::set('convert_to_primary', $convertToPrimary); Preferences::set('convert_to_primary', $convertToPrimary);

View File

@@ -25,16 +25,20 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Transaction; namespace FireflyIII\Http\Controllers\Transaction;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\TransactionGroup; use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\AuditLogEntry\ALERepositoryInterface; use FireflyIII\Repositories\AuditLogEntry\ALERepositoryInterface;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface; use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\TransactionGroupTransformer; use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User;
use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\Factory;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\View\View; use Illuminate\View\View;
use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/** /**
* Class ShowController * Class ShowController
@@ -57,7 +61,7 @@ class ShowController extends Controller
$this->repository = app(TransactionGroupRepositoryInterface::class); $this->repository = app(TransactionGroupRepositoryInterface::class);
$this->aleRepository = app(ALERepositoryInterface::class); $this->aleRepository = app(ALERepositoryInterface::class);
app('view')->share('title', (string) trans('firefly.transactions')); app('view')->share('title', (string)trans('firefly.transactions'));
app('view')->share('mainTitleIcon', 'fa-exchange'); app('view')->share('mainTitleIcon', 'fa-exchange');
return $next($request); return $next($request);
@@ -80,38 +84,62 @@ class ShowController extends Controller
*/ */
public function show(TransactionGroup $transactionGroup) public function show(TransactionGroup $transactionGroup)
{ {
/** @var User $admin */
$admin = auth()->user();
// use new group collector:
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setUser($admin)->setTransactionGroup($transactionGroup)->withAPIInformation();
$selectedGroup = $collector->getGroups()->first();
if (null === $selectedGroup) {
throw new NotFoundHttpException();
}
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($admin);
$selectedGroup = $enrichment->enrichSingle($selectedGroup);
/** @var null|TransactionJournal $first */ /** @var null|TransactionJournal $first */
$first = $transactionGroup->transactionJournals()->first(['transaction_journals.*']); $first = $transactionGroup->transactionJournals()->first(['transaction_journals.*']);
$splits = $transactionGroup->transactionJournals()->count(); $splits = $transactionGroup->transactionJournals()->count();
$splits = count($selectedGroup['transactions']);
$keys = array_keys($selectedGroup['transactions']);
$first = $selectedGroup['transactions'][array_shift($keys)];
unset($keys);
if (null === $first) { if (null === $first) {
throw new FireflyException('This transaction is broken :(.'); throw new FireflyException('This transaction is broken :(.');
} }
$type = (string)trans(sprintf('firefly.%s', $first['transaction_type_type']));
$type = (string) trans(sprintf('firefly.%s', $first->transactionType->type)); $title = 1 === $splits ? $first['description'] : $selectedGroup['title'];
$title = 1 === $splits ? $first->description : $transactionGroup->title;
$subTitle = sprintf('%s: "%s"', $type, $title); $subTitle = sprintf('%s: "%s"', $type, $title);
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($admin);
$selectedGroup = $enrichment->enrichSingle($selectedGroup);
/** @var TransactionGroupTransformer $transformer */ /** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class); $transformer = app(TransactionGroupTransformer::class);
$transformer->setParameters(new ParameterBag()); $transformer->setParameters(new ParameterBag());
$groupArray = $transformer->transformObject($transactionGroup); $groupArray = $transformer->transformObject($transactionGroup);
// do some calculations: // do some calculations:
$amounts = $this->getAmounts($groupArray); $amounts = $this->getAmounts($selectedGroup);
$accounts = $this->getAccounts($groupArray); $accounts = $this->getAccounts($selectedGroup);
foreach (array_keys($groupArray['transactions']) as $index) { foreach (array_keys($selectedGroup['transactions']) as $index) {
$groupArray['transactions'][$index]['tags'] = $this->repository->getTagObjects( $selectedGroup['transactions'][$index]['tags'] = $this->repository->getTagObjects((int)$selectedGroup['transactions'][$index]['transaction_journal_id']);
(int) $groupArray['transactions'][$index]['transaction_journal_id']
);
} }
// get audit log entries: // get audit log entries:
$groupLogEntries = $this->aleRepository->getForObject($transactionGroup); $groupLogEntries = $this->aleRepository->getForObject($transactionGroup);
$logEntries = []; $logEntries = [];
foreach ($transactionGroup->transactionJournals as $journal) { foreach ($selectedGroup['transactions'] as $journal) {
$logEntries[$journal->id] = $this->aleRepository->getForObject($journal); $logEntries[$journal['transaction_journal_id']] = $this->aleRepository->getForId(TransactionJournal::class, $journal['transaction_journal_id']);
} }
$events = $this->repository->getPiggyEvents($transactionGroup); $events = $this->repository->getPiggyEvents($transactionGroup);
@@ -129,6 +157,7 @@ class ShowController extends Controller
'groupLogEntries', 'groupLogEntries',
'subTitle', 'subTitle',
'splits', 'splits',
'selectedGroup',
'groupArray', 'groupArray',
'events', 'events',
'attachments', 'attachments',
@@ -142,34 +171,38 @@ class ShowController extends Controller
{ {
$amounts = []; $amounts = [];
foreach ($group['transactions'] as $transaction) { foreach ($group['transactions'] as $transaction) {
// add normal amount:
$symbol = $transaction['currency_symbol']; $symbol = $transaction['currency_symbol'];
if (!array_key_exists($symbol, $amounts)) { $amounts[$symbol] ??= [
$amounts[$symbol] = [
'amount' => '0', 'amount' => '0',
'symbol' => $symbol, 'symbol' => $symbol,
'decimal_places' => $transaction['currency_decimal_places'], 'decimal_places' => $transaction['currency_decimal_places'],
]; ];
} $amounts[$symbol]['amount'] = bcadd($amounts[$symbol]['amount'], (string)$transaction['amount']);
$amounts[$symbol]['amount'] = bcadd($amounts[$symbol]['amount'], (string) $transaction['amount']);
if (null !== $transaction['foreign_amount'] && '' !== $transaction['foreign_amount'] // add foreign amount:
&& 0 !== bccomp( if (null !== $transaction['foreign_amount'] && '' !== $transaction['foreign_amount'] && 0 !== bccomp('0', (string)$transaction['foreign_amount'])) {
'0',
(string) $transaction['foreign_amount']
)) {
// same for foreign currency: // same for foreign currency:
$foreignSymbol = $transaction['foreign_currency_symbol']; $foreignSymbol = $transaction['foreign_currency_symbol'];
if (!array_key_exists($foreignSymbol, $amounts)) { $amounts[$foreignSymbol] ??= [
$amounts[$foreignSymbol] = [
'amount' => '0', 'amount' => '0',
'symbol' => $foreignSymbol, 'symbol' => $foreignSymbol,
'decimal_places' => $transaction['foreign_currency_decimal_places'], 'decimal_places' => $transaction['foreign_currency_decimal_places'],
]; ];
$amounts[$foreignSymbol]['amount'] = bcadd($amounts[$foreignSymbol]['amount'], (string)$transaction['foreign_amount']);
} }
$amounts[$foreignSymbol]['amount'] = bcadd( // add primary currency amount
$amounts[$foreignSymbol]['amount'], if (null !== $transaction['pc_amount'] && $transaction['currency_id'] !== $this->primaryCurrency->id) {
(string) $transaction['foreign_amount'] // same for foreign currency:
); $primarySymbol = $this->primaryCurrency->symbol;
$amounts[$primarySymbol] ??= [
'amount' => '0',
'symbol' => $this->primaryCurrency->symbol,
'decimal_places' => $this->primaryCurrency->decimal_places,
];
$amounts[$primarySymbol]['amount'] = bcadd($amounts[$primarySymbol]['amount'], (string)$transaction['pc_amount']);
} }
} }
return $amounts; return $amounts;
@@ -184,16 +217,16 @@ class ShowController extends Controller
foreach ($group['transactions'] as $transaction) { foreach ($group['transactions'] as $transaction) {
$accounts['source'][] = [ $accounts['source'][] = [
'type' => $transaction['source_type'], 'type' => $transaction['source_account_type'],
'id' => $transaction['source_id'], 'id' => $transaction['source_account_id'],
'name' => $transaction['source_name'], 'name' => $transaction['source_account_name'],
'iban' => $transaction['source_iban'], 'iban' => $transaction['source_account_iban'],
]; ];
$accounts['destination'][] = [ $accounts['destination'][] = [
'type' => $transaction['destination_type'], 'type' => $transaction['destination_account_type'],
'id' => $transaction['destination_id'], 'id' => $transaction['destination_account_id'],
'name' => $transaction['destination_name'], 'name' => $transaction['destination_account_name'],
'iban' => $transaction['destination_iban'], 'iban' => $transaction['destination_account_iban'],
]; ];
} }

View File

@@ -52,4 +52,10 @@ class ALERepository implements ALERepositoryInterface
return $auditLogEntry; return $auditLogEntry;
} }
public function getForId(string $model, int $modelId): Collection
{
// all Models have an ID.
return AuditLogEntry::where('auditable_id', $modelId)->where('auditable_type', $model)->get();
}
} }

View File

@@ -45,6 +45,8 @@ use Illuminate\Support\Collection;
interface ALERepositoryInterface interface ALERepositoryInterface
{ {
public function getForObject(Model $model): Collection; public function getForObject(Model $model): Collection;
public function getForId(string $model, int $modelId): Collection;
public function store(array $data): AuditLogEntry; public function store(array $data): AuditLogEntry;
} }

View File

@@ -117,18 +117,23 @@ class Amount
public function convertToPrimary(?User $user = null): bool public function convertToPrimary(?User $user = null): bool
{ {
$instance = PreferencesSingleton::getInstance(); $instance = PreferencesSingleton::getInstance();
$pref = $instance->getPreference('convert_to_primary');
if (null === $pref) {
if (!$user instanceof User) { if (!$user instanceof User) {
$pref = $instance->getPreference('convert_to_primary_no_user');
if (null === $pref) {
$res = true === Preferences::get('convert_to_primary', false)->data && true === config('cer.enabled'); $res = true === Preferences::get('convert_to_primary', false)->data && true === config('cer.enabled');
$instance->setPreference('convert_to_primary', $res); $instance->setPreference('convert_to_primary_no_user', $res);
return $res;
}
return $pref;
}
$key = sprintf('convert_to_primary_%d', $user->id);
$pref = $instance->getPreference($key);
if(null === $pref) {
$res = true === Preferences::getForUser($user, 'convert_to_primary', false)->data && true === config('cer.enabled');
$instance->setPreference($key, $res);
return $res; return $res;
} }
$res = true === Preferences::getForUser($user, 'convert_to_primary', false)->data && true === config('cer.enabled');
$instance->setPreference('convert_to_primary', $res);
return $res;
}
return $pref; return $pref;
} }

View File

@@ -67,7 +67,7 @@ trait ChartGeneration
/** @var AccountRepositoryInterface $accountRepos */ /** @var AccountRepositoryInterface $accountRepos */
$accountRepos = app(AccountRepositoryInterface::class); $accountRepos = app(AccountRepositoryInterface::class);
$default = app('amount')->getPrimaryCurrency(); $primary = app('amount')->getPrimaryCurrency();
$chartData = []; $chartData = [];
Log::debug(sprintf('Start of accountBalanceChart(list, %s, %s)', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s'))); Log::debug(sprintf('Start of accountBalanceChart(list, %s, %s)', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
@@ -75,10 +75,10 @@ trait ChartGeneration
/** @var Account $account */ /** @var Account $account */
foreach ($accounts as $account) { foreach ($accounts as $account) {
Log::debug(sprintf('Now at account #%d ("%s)', $account->id, $account->name)); Log::debug(sprintf('Now at account #%d ("%s)', $account->id, $account->name));
$currency = $accountRepos->getAccountCurrency($account) ?? $default; $currency = $accountRepos->getAccountCurrency($account) ?? $primary;
$usePrimary = $convertToPrimary && $default->id !== $currency->id; $usePrimary = $convertToPrimary && $primary->id !== $currency->id;
$field = $convertToPrimary ? 'pc_balance' : 'balance'; $field = $convertToPrimary ? 'pc_balance' : 'balance';
$currency = $usePrimary ? $default : $currency; $currency = $usePrimary ? $primary : $currency;
Log::debug(sprintf('Will use field %s', $field)); Log::debug(sprintf('Will use field %s', $field));
$currentSet = [ $currentSet = [
'label' => $account->name, 'label' => $account->name,

View File

@@ -22,6 +22,10 @@ class PreferencesSingleton
return self::$instance; return self::$instance;
} }
public function resetPreferences(): void {
$this->preferences = [];
}
public function setPreference(string $key, mixed $value): void public function setPreference(string $key, mixed $value): void
{ {
$this->preferences[$key] = $value; $this->preferences[$key] = $value;

View File

@@ -64,7 +64,7 @@
<tbody> <tbody>
<tr> <tr>
<td style="width:40%;">{{ trans('list.type') }}</td> <td style="width:40%;">{{ trans('list.type') }}</td>
<td>{{ first.transactiontype.type|_ }}</td> <td>{{ first.transaction_type_type|_ }}</td>
</tr> </tr>
<tr> <tr>
<td>{{ trans('list.description') }}</td> <td>{{ trans('list.description') }}</td>
@@ -113,7 +113,7 @@
<div class="box-body no-padding"> <div class="box-body no-padding">
<table class="table table-hover"> <table class="table table-hover">
<tbody> <tbody>
{% if first.transactiontype.type != 'Withdrawal' or splits == 1 %} {% if first.transaction_type_type != 'Withdrawal' or splits == 1 %}
<tr> <tr>
<td style="width:40%;"> <td style="width:40%;">
{{ trans_choice('firefly.source_accounts', accounts['source']|length ) }} {{ trans_choice('firefly.source_accounts', accounts['source']|length ) }}
@@ -134,7 +134,7 @@
</tr> </tr>
{% endif %} {% endif %}
{% if first.transactiontype.type != 'Deposit' or splits == 1 %} {% if first.transaction_type_type != 'Deposit' or splits == 1 %}
<tr> <tr>
<td> <td>
{{ trans_choice('firefly.destination_accounts', accounts['destination']|length ) }} {{ trans_choice('firefly.destination_accounts', accounts['destination']|length ) }}
@@ -159,17 +159,17 @@
<td style="width:30%;">{{ 'total_amount'|_ }}</td> <td style="width:30%;">{{ 'total_amount'|_ }}</td>
<td> <td>
{% for amount in amounts %} {% for amount in amounts %}
{% if first.transactiontype.type == 'Withdrawal' %} {% if first.transaction_type_type == 'Withdrawal' %}
{{ formatAmountBySymbol(amount.amount*-1,amount.symbol, amount.decimal_places) }}{% if loop.index0 != amounts|length -1 %}, {% endif %} {{ formatAmountBySymbol(amount.amount*-1,amount.symbol, amount.decimal_places) }}{% if loop.index0 != amounts|length -1 %}, {% endif %}
{% elseif first.transactiontype.type == 'Deposit' %} {% elseif first.transaction_type_type == 'Deposit' %}
{{ formatAmountBySymbol(amount.amount,amount.symbol, amount.decimal_places) }}{% if loop.index0 != amounts|length -1 %}, {% endif %} {{ formatAmountBySymbol(amount.amount,amount.symbol, amount.decimal_places) }}{% if loop.index0 != amounts|length -1 %}, {% endif %}
{% elseif first.transactiontype.type == 'Transfer' %} {% elseif first.transaction_type_type == 'Transfer' %}
<span class="text-info money-transfer"> <span class="text-info money-transfer">
{{ formatAmountBySymbol(amount.amount, amount.symbol, amount.decimal_places, false) }}{% if loop.index0 != amounts|length -1 %}, {% endif %} {{ formatAmountBySymbol(amount.amount, amount.symbol, amount.decimal_places, false) }}{% if loop.index0 != amounts|length -1 %}, {% endif %}
</span> </span>
{% elseif first.transactiontype.type == 'Opening balance' %} {% elseif first.transaction_type_type == 'Opening balance' %}
{# Opening balance stored amount is always negative: find out which way the money goes #} {# Opening balance stored amount is always negative: find out which way the money goes #}
{% if groupArray.transactions[0].source_type == 'Initial balance account' %} {% if groupArray.transactions[0].source_account_type == 'Initial balance account' %}
{{ formatAmountBySymbol(amount.amount*-1,amount.symbol, amount.decimal_places) }} {{ formatAmountBySymbol(amount.amount*-1,amount.symbol, amount.decimal_places) }}
{% else %} {% else %}
{{ formatAmountBySymbol(amount.amount,amount.symbol, amount.decimal_places) }} {{ formatAmountBySymbol(amount.amount,amount.symbol, amount.decimal_places) }}
@@ -202,7 +202,7 @@
{% set boxSize = 4 %} {% set boxSize = 4 %}
{% endif %} {% endif %}
<div class="row"> <div class="row">
{% for index,journal in groupArray.transactions %} {% for index,journal in selectedGroup.transactions %}
<div class="col-lg-{{ boxSize }}"> <div class="col-lg-{{ boxSize }}">
<div class="box"> <div class="box">
<div class="box-header with-border"> <div class="box-header with-border">
@@ -289,48 +289,74 @@
<table class="table"> <table class="table">
<tr> <tr>
<td colspan="2"> <td colspan="2">
<!-- type is: "{{ first.transaction_type_type }}" -->
<!-- type is: "{{ first.transactiontype.type }}" --> {% if 'Cash account' == journal.source_account_type %}
{% if 'Cash account' == journal.source_type %}
<span class="text-success">({{ 'cash'|_ }})</span> <span class="text-success">({{ 'cash'|_ }})</span>
{% else %} {% else %}
<a href="{{ route('accounts.show', journal.source_id) }}" <a href="{{ route('accounts.show', journal.source_account_id) }}"
title="{{ journal.source_iban|default(journal.source_name) }}">{{ journal.source_name }}</a> &rarr; title="{{ journal.source_iban|default(journal.source_account_name) }}">{{ journal.source_account_name }}</a> &rarr;
{% endif %} {% endif %}
{% if first.transactiontype.type == 'Withdrawal' %} {% if first.transaction_type_type == 'Withdrawal' %}
{{ formatAmountBySymbol(journal.amount*-1, journal.currency_symbol, journal.currency_decimal_places) }} {{ formatAmountBySymbol(journal.amount*-1, journal.currency_symbol, journal.currency_decimal_places) }}
{% elseif first.transactiontype.type == 'Deposit' %} {% elseif first.transaction_type_type == 'Deposit' %}
{{ formatAmountBySymbol(journal.amount, journal.currency_symbol, journal.currency_decimal_places) }} {{ formatAmountBySymbol(journal.amount, journal.currency_symbol, journal.currency_decimal_places) }}
{% elseif first.transactiontype.type == 'Transfer' or first.transactiontype.type == 'Opening balance' %} {% elseif first.transaction_type_type == 'Transfer' or first.transaction_type_type == 'Opening balance' %}
<span class="text-info money-transfer"> <span class="text-info money-transfer">
{{ formatAmountBySymbol(journal.amount, journal.currency_symbol, journal.currency_decimal_places, false) }} {{ formatAmountBySymbol(journal.amount, journal.currency_symbol, journal.currency_decimal_places, false) }}
</span> </span>
{% elseif first.transactiontype.type == 'Liability credit' %} {% elseif first.transaction_type_type == 'Liability credit' %}
<span class="text-info money-transfer"> <span class="text-info money-transfer">
{{ formatAmountBySymbol(journal.amount*-1, journal.currency_symbol, journal.currency_decimal_places, false) }} {{ formatAmountBySymbol(journal.amount*-1, journal.currency_symbol, journal.currency_decimal_places, false) }}
</span> </span>
{% endif %} {% endif %}
<!-- do primary currency amount -->
{% if null != journal.pc_amount and primaryCurrency.id != journal.currency_id %}
{% if first.transaction_type_type == 'Withdrawal' %}
({{ formatAmountBySymbol(journal.pc_amount*-1, primaryCurrency.symbol, primaryCurrency.decimal_places) }})
{% elseif first.transaction_type_type == 'Deposit' %}
({{ formatAmountBySymbol(journal.pc_amount, primaryCurrency.symbol, primaryCurrency.decimal_places) }})
{% elseif first.transaction_type_type == 'Transfer' %}
<span class="text-info money-transfer">
({{ formatAmountBySymbol(journal.pc_amount, primaryCurrency.symbol, primaryCurrency.decimal_places, false) }})
</span>
{% endif %}
{% endif %}
<!-- do foreign amount --> <!-- do foreign amount -->
{% if null != journal.foreign_amount %} {% if null != journal.foreign_amount %}
{% if first.transactiontype.type == 'Withdrawal' %} {% if first.transaction_type_type == 'Withdrawal' %}
({{ formatAmountBySymbol(journal.foreign_amount*-1, journal.foreign_currency_symbol, journal.foreign_currency_decimal_places) }}) ({{ formatAmountBySymbol(journal.foreign_amount*-1, journal.foreign_currency_symbol, journal.foreign_currency_decimal_places) }})
{% elseif first.transactiontype.type == 'Deposit' %} {% elseif first.transaction_type_type == 'Deposit' %}
({{ formatAmountBySymbol(journal.foreign_amount, journal.foreign_currency_symbol, journal.foreign_currency_decimal_places) }}) ({{ formatAmountBySymbol(journal.foreign_amount, journal.foreign_currency_symbol, journal.foreign_currency_decimal_places) }})
{% elseif first.transactiontype.type == 'Transfer' %} {% elseif first.transaction_type_type == 'Transfer' %}
<span class="text-info money-transfer"> <span class="text-info money-transfer">
({{ formatAmountBySymbol(journal.foreign_amount, journal.foreign_currency_symbol, journal.foreign_currency_decimal_places, false) }}) ({{ formatAmountBySymbol(journal.foreign_amount, journal.foreign_currency_symbol, journal.foreign_currency_decimal_places, false) }})
</span> </span>
{% endif %} {% endif %}
{% endif %} {% endif %}
<!-- do foreign PC amount -->
{% if null != journal.pc_foreign_amount %}
{% if first.transaction_type_type == 'Withdrawal' %}
({{ formatAmountBySymbol(journal.pc_foreign_amount*-1, primaryCurrency.symbol, primaryCurrency.decimal_places) }})
{% elseif first.transaction_type_type == 'Deposit' %}
({{ formatAmountBySymbol(journal.pc_foreign_amount, primaryCurrency.symbol, primaryCurrency.decimal_places) }})
{% elseif first.transaction_type_type == 'Transfer' %}
<span class="text-info money-transfer">
({{ formatAmountBySymbol(journal.pc_foreign_amount, primaryCurrency.symbol, primaryCurrency.decimal_places, false) }})
</span>
{% endif %}
{% endif %}
&rarr; &rarr;
{% if 'Cash account' == journal.destination_type %} {% if 'Cash account' == journal.destination_account_type %}
<span class="text-success">({{ 'cash'|_ }})</span> <span class="text-success">({{ 'cash'|_ }})</span>
{% else %} {% else %}
<a href="{{ route('accounts.show', journal.destination_id) }}" <a href="{{ route('accounts.show', journal.destination_account_id) }}"
title="{{ journal.destination_iban|default(journal.destination_name) }}">{{ journal.destination_name }}</a> title="{{ journal.destination_iban|default(journal.destination_account_name) }}">{{ journal.destination_account_name }}</a>
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
@@ -346,7 +372,7 @@
</td> </td>
</tr> </tr>
{% endif %} {% endif %}
{% if null != journal.budget_id and first.transactiontype.type == 'Withdrawal' %} {% if null != journal.budget_id and first.transaction_type_type == 'Withdrawal' %}
<tr> <tr>
<td style="width:40%;">{{ 'budget'|_ }}</td> <td style="width:40%;">{{ 'budget'|_ }}</td>
<td> <td>
@@ -354,7 +380,7 @@
</td> </td>
</tr> </tr>
{% endif %} {% endif %}
{% if null != journal.bill_id and first.transactiontype.type == 'Withdrawal' %} {% if null != journal.bill_id and first.transaction_type_type == 'Withdrawal' %}
<tr> <tr>
<td style="width:40%;">{{ 'bill'|_ }}</td> <td style="width:40%;">{{ 'bill'|_ }}</td>
<td> <td>

View File

@@ -24,255 +24,9 @@ declare(strict_types=1);
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
/*
*
* ____ ____ ___ .______ ______ __ __ .___________. _______ _______.
* \ \ / / |__ \ | _ \ / __ \ | | | | | || ____| / |
* \ \/ / ) | | |_) | | | | | | | | | `---| |----`| |__ | (----`
* \ / / / | / | | | | | | | | | | | __| \ \
* \ / / /_ | |\ \----.| `--' | | `--' | | | | |____.----) |
* \__/ |____| | _| `._____| \______/ \______/ |__| |_______|_______/
*/
// AUTOCOMPLETE ROUTES
Route::group(
[
'namespace' => 'FireflyIII\Api\V2\Controllers\Autocomplete',
'prefix' => 'v2/autocomplete',
'as' => 'api.v2.autocomplete.',
],
static function (): void {
Route::get('accounts', ['uses' => 'AccountController@accounts', 'as' => 'accounts']);
// Route::get('categories', ['uses' => 'CategoryController@categories', 'as' => 'categories']);
// Route::get('tags', ['uses' => 'TagController@tags', 'as' => 'tags']);
// Route::get('transaction-descriptions', ['uses' => 'TransactionController@transactionDescriptions', 'as' => 'transaction-descriptions']);
}
);
// USER GROUP ROUTES
Route::group(
[
'namespace' => 'FireflyIII\Api\V2\Controllers\UserGroup',
'prefix' => 'v2/user-groups',
'as' => 'api.v2.user-groups.',
],
static function (): void {
Route::get('', ['uses' => 'IndexController@index', 'as' => 'index']);
Route::post('', ['uses' => 'StoreController@store', 'as' => 'store']);
Route::get('{userGroup}', ['uses' => 'ShowController@show', 'as' => 'show']);
// Route::put('{userGroup}', ['uses' => 'UpdateController@update', 'as' => 'update']);
// Route::post('{userGroup}/use', ['uses' => 'UpdateController@useUserGroup', 'as' => 'use']);
// Route::put('{userGroup}/update-membership', ['uses' => 'UpdateController@updateMembership', 'as' => 'updateMembership']);
// Route::delete('{userGroup}', ['uses' => 'DestroyController@destroy', 'as' => 'destroy']);
}
);
// CHART ROUTES
Route::group(
[
'namespace' => 'FireflyIII\Api\V2\Controllers\Chart',
'prefix' => 'v2/chart',
'as' => 'api.v2.chart.',
],
static function (): void {
// Route::get('account/dashboard', ['uses' => 'AccountController@dashboard', 'as' => 'account.dashboard']);
// Route::get('budget/dashboard', ['uses' => 'BudgetController@dashboard', 'as' => 'budget.dashboard']);
// Route::get('category/dashboard', ['uses' => 'CategoryController@dashboard', 'as' => 'category.dashboard']);
Route::get('balance/balance', ['uses' => 'BalanceController@balance', 'as' => 'balance.balance']);
}
);
// CURRENCY ROUTES
Route::group(
[
'namespace' => 'FireflyIII\Api\V2\Controllers\Model\TransactionCurrency',
'prefix' => 'v2/currencies',
'as' => 'api.v2.currencies.',
],
static function (): void {
Route::get('', ['uses' => 'IndexController@index', 'as' => 'index']);
Route::get('{currency_code}', ['uses' => 'ShowController@show', 'as' => 'show']);
// Route::post('', ['uses' => 'StoreController@store', 'as' => 'store']);
//
// Route::put('{userGroup}', ['uses' => 'UpdateController@update', 'as' => 'update']);
// Route::post('{userGroup}/use', ['uses' => 'UpdateController@useUserGroup', 'as' => 'use']);
// Route::put('{userGroup}/update-membership', ['uses' => 'UpdateController@updateMembership', 'as' => 'updateMembership']);
// Route::delete('{userGroup}', ['uses' => 'DestroyController@destroy', 'as' => 'destroy']);
}
);
// V2 API route for Summary boxes
// BASIC
// Route::group(
// [
// 'namespace' => 'FireflyIII\Api\V2\Controllers\Summary',
// 'prefix' => 'v2/summary',
// 'as' => 'api.v2.summary.',
// ],
// static function (): void {
// // Route::get('basic', ['uses' => 'BasicController@basic', 'as' => 'basic']);
// }
// );
// // V2 API route for all kinds of Transaction lists.
// // A lot of endpoints involve transactions. So any time Firefly III needs to list transactions
// // it's coming from these endpoints.
// Route::group(
// [
// 'namespace' => 'FireflyIII\Api\V2\Controllers\Transaction\List',
// 'prefix' => 'v2',
// 'as' => 'api.v2.',
// ],
// static function (): void {
// // basic list
// // Route::get('transactions', ['uses' => 'TransactionController@list', 'as' => 'transactions.list']);
//
// // list by parent or related object.
// // note how the check is done on the user group, not the user itself.
// // Route::get('accounts/{userGroupAccount}/transactions', ['uses' => 'AccountController@list', 'as' => 'accounts.transactions']);
// }
// );
// V2 API routes for auto complete
//
// // V2 API route for net worth endpoint(s);
// Route::group(
// [
// 'namespace' => 'FireflyIII\Api\V2\Controllers\Summary',
// 'prefix' => 'v2/net-worth',
// 'as' => 'api.v2.net-worth.',
// ],
// static function (): void {
// // Route::get('', ['uses' => 'NetWorthController@get', 'as' => 'index']);
// }
// );
//
// // // V2 API route for accounts.
// // Route::group(
// // [
// // 'namespace' => 'FireflyIII\Api\V2\Controllers\Model\Account',
// // 'prefix' => 'v2/accounts',
// // 'as' => 'api.v2.accounts.',
// // ],
// // static function (): void {
// // Route::get('', ['uses' => 'IndexController@index', 'as' => 'index']);
// // Route::get('{account}', ['uses' => 'ShowController@show', 'as' => 'show']);
// // Route::put('{account}', ['uses' => 'UpdateController@update', 'as' => 'update']);
// // }
// // );
//
// // V2 API route for subscriptions.
// Route::group(
// [
// 'namespace' => 'FireflyIII\Api\V2\Controllers\Model\Bill',
// 'prefix' => 'v2/subscriptions',
// 'as' => 'api.v2.subscriptions.',
// ],
// static function (): void {
// // Route::get('', ['uses' => 'IndexController@index', 'as' => 'index']);
// // Route::get('{userGroupBill}', ['uses' => 'ShowController@show', 'as' => 'show']);
// // Route::get('sum/paid', ['uses' => 'SumController@paid', 'as' => 'sum.paid']);
// // Route::get('sum/unpaid', ['uses' => 'SumController@unpaid', 'as' => 'sum.unpaid']);
// }
// );
//
// // V2 API route for piggy banks.
// Route::group(
// [
// 'namespace' => 'FireflyIII\Api\V2\Controllers\Model\PiggyBank',
// 'prefix' => 'v2/piggy-banks',
// 'as' => 'api.v2.piggy-banks.',
// ],
// static function (): void {
// // Route::get('', ['uses' => 'IndexController@index', 'as' => 'index']);
// }
// );
//
// // V2 API route for transaction currencies
// Route::group(
// [
// 'namespace' => 'FireflyIII\Api\V2\Controllers\Model\Currency',
// 'prefix' => 'v2/currencies',
// 'as' => 'api.v2.currencies.',
// ],
// static function (): void {
// // Route::get('', ['uses' => 'IndexController@index', 'as' => 'index']);
// }
// );
//
// // V2 API route for transactions
// Route::group(
// [
// 'namespace' => 'FireflyIII\Api\V2\Controllers\Model\Transaction',
// 'prefix' => 'v2/transactions',
// 'as' => 'api.v2.transactions.',
// ],
// static function (): void {
// // Route::post('', ['uses' => 'StoreController@post', 'as' => 'store']);
// // Route::get('{userGroupTransaction}', ['uses' => 'ShowController@show', 'as' => 'show']);
// // Route::put('{userGroupTransaction}', ['uses' => 'UpdateController@update', 'as' => 'update']);
// }
// );
// // infinite (transactions) list:
// Route::group(
// [
// 'namespace' => 'FireflyIII\Api\V2\Controllers\Transaction\List',
// 'prefix' => 'v2/infinite/transactions',
// 'as' => 'api.v2.infinite.transactions.',
// ],
// static function (): void {
// // Route::get('', ['uses' => 'TransactionController@infiniteList', 'as' => 'list']);
// }
// );
//
// // V2 API route for budgets and budget limits:
// Route::group(
// [
// 'namespace' => 'FireflyIII\Api\V2\Controllers\Model',
// 'prefix' => 'v2/budgets',
// 'as' => 'api.v2.budgets',
// ],
// static function (): void {
// // Route::get('', ['uses' => 'Budget\IndexController@index', 'as' => 'index']);
// // Route::get('{budget}', ['uses' => 'Budget\ShowController@show', 'as' => 'show']);
// // Route::get('{budget}/limits', ['uses' => 'BudgetLimit\IndexController@index', 'as' => 'budget-limits.index']);
// // Route::get('sum/budgeted', ['uses' => 'Budget\SumController@budgeted', 'as' => 'sum.budgeted']);
// // Route::get('sum/spent', ['uses' => 'Budget\SumController@spent', 'as' => 'sum.spent']);
// // Route::get('{budget}/budgeted', ['uses' => 'Budget\ShowController@budgeted', 'as' => 'budget.budgeted']);
// // Route::get('{budget}/spent', ['uses' => 'Budget\ShowController@spent', 'as' => 'budget.spent']);
// }
// );
//
// // V2 API route for system
// Route::group(
// [
// 'namespace' => 'FireflyIII\Api\V2\Controllers\System',
// 'prefix' => 'v2',
// 'as' => 'api.v2.system.',
// ],
// static function (): void {
// // Route::get('preferences/{preference}', ['uses' => 'PreferencesController@get', 'as' => 'preferences.get']);
// }
// );
//
// V2 JSON API ROUTES
// JsonApiRoute::server('v2')->prefix('v2')
// ->resources(function (ResourceRegistrar $server): void {
// // ACCOUNTS
// $server->resource('accounts', AccountController::class)
// ->relationships(function (Relationships $relations): void {
// $relations->hasOne('user')->readOnly();
// })
// ;
//
// // USERS
// $server->resource('users', JsonApiController::class)->readOnly()->relationships(function (Relationships $relations): void {
// $relations->hasMany('accounts')->readOnly();
// });
// })
// ;
/* /*
* ____ ____ __ .______ ______ __ __ .___________. _______ _______. * ____ ____ __ .______ ______ __ __ .___________. _______ _______.
@@ -330,6 +84,21 @@ Route::group(
); );
// CHART ROUTES. // CHART ROUTES.
// chart balance
// CHART ROUTES
Route::group(
[
'namespace' => 'FireflyIII\Api\V2\Controllers\Chart',
'prefix' => 'v1/chart/balance',
'as' => 'api.v1.chart.balance',
],
static function (): void {
Route::get('balance', ['uses' => 'BalanceController@balance', 'as' => 'balance.balance']);
}
);
// Chart accounts // Chart accounts
Route::group( Route::group(
[ [