Code cleanup

This commit is contained in:
James Cole
2021-03-21 09:15:40 +01:00
parent da1751940e
commit 206845575c
317 changed files with 7418 additions and 7362 deletions

View File

@@ -27,7 +27,6 @@ use FireflyIII\Models\TransactionCurrency;
use FireflyIII\User;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Support\Collection;
use Log;
use NumberFormatter;
/**
@@ -37,6 +36,225 @@ use NumberFormatter;
*/
class Amount
{
/**
* This method will properly format the given number, in color or "black and white",
* as a currency, given two things: the currency required and the current locale.
*
* @param TransactionCurrency $format
* @param string $amount
* @param bool $coloured
*
* @return string
*
*/
public function formatAnything(TransactionCurrency $format, string $amount, bool $coloured = null): string
{
return $this->formatFlat($format->symbol, (int)$format->decimal_places, $amount, $coloured);
}
/**
* This method will properly format the given number, in color or "black and white",
* as a currency, given two things: the currency required and the current locale.
*
* @param string $symbol
* @param int $decimalPlaces
* @param string $amount
* @param bool $coloured
*
* @return string
*
* @noinspection MoreThanThreeArgumentsInspection
*/
public function formatFlat(string $symbol, int $decimalPlaces, string $amount, bool $coloured = null): string
{
$locale = app('steam')->getLocale();
$coloured = $coloured ?? true;
$fmt = new NumberFormatter($locale, NumberFormatter::CURRENCY);
$fmt->setSymbol(NumberFormatter::CURRENCY_SYMBOL, $symbol);
$fmt->setAttribute(NumberFormatter::MIN_FRACTION_DIGITS, $decimalPlaces);
$fmt->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $decimalPlaces);
$result = $fmt->format((float)$amount);
if (true === $coloured) {
if ($amount > 0) {
return sprintf('<span class="text-success">%s</span>', $result);
}
if ($amount < 0) {
return sprintf('<span class="text-danger">%s</span>', $result);
}
return sprintf('<span style="color:#999">%s</span>', $result);
}
return $result;
}
/**
* @return Collection
*/
public function getAllCurrencies(): Collection
{
return TransactionCurrency::orderBy('code', 'ASC')->get();
}
/**
* @return Collection
*/
public function getCurrencies(): Collection
{
return TransactionCurrency::where('enabled', true)->orderBy('code', 'ASC')->get();
}
/**
* @return string
*/
public function getCurrencyCode(): string
{
$cache = new CacheProperties;
$cache->addProperty('getCurrencyCode');
if ($cache->has()) {
return $cache->get(); // @codeCoverageIgnore
}
$currencyPreference = app('preferences')->get('currencyPreference', config('firefly.default_currency', 'EUR'));
$currency = TransactionCurrency::where('code', $currencyPreference->data)->first();
if ($currency) {
$cache->store($currency->code);
return $currency->code;
}
$cache->store(config('firefly.default_currency', 'EUR'));
return (string)config('firefly.default_currency', 'EUR');
}
/**
* @return TransactionCurrency
*/
public function getDefaultCurrency(): TransactionCurrency
{
/** @var User $user */
$user = auth()->user();
return $this->getDefaultCurrencyByUser($user);
}
/**
* @param User $user
*
* @return TransactionCurrency
*/
public function getDefaultCurrencyByUser(User $user): TransactionCurrency
{
$cache = new CacheProperties;
$cache->addProperty('getDefaultCurrency');
$cache->addProperty($user->id);
if ($cache->has()) {
return $cache->get(); // @codeCoverageIgnore
}
$currencyPreference = app('preferences')->getForUser($user, 'currencyPreference', config('firefly.default_currency', 'EUR'));
$currencyPrefStr = $currencyPreference ? $currencyPreference->data : 'EUR';
// at this point the currency preference could be encrypted, if coming from an old version.
$currencyCode = $this->tryDecrypt((string)$currencyPrefStr);
// could still be json encoded:
if (strlen($currencyCode) > 3) {
$currencyCode = json_decode($currencyCode, true, 512, JSON_THROW_ON_ERROR) ?? 'EUR';
}
/** @var TransactionCurrency $currency */
$currency = TransactionCurrency::where('code', $currencyCode)->first();
if (null === $currency) {
// get EUR
$currency = TransactionCurrency::where('code', 'EUR')->first();
}
$cache->store($currency);
return $currency;
}
/**
* @param string $value
*
* @return string
*/
private function tryDecrypt(string $value): string
{
try {
$value = Crypt::decrypt($value); // verified
} catch (DecryptException $e) {
// ignore decryption error.
}
return $value;
}
/**
* This method returns the correct format rules required by accounting.js,
* the library used to format amounts in charts.
*
* Used only in one place.
*
* @return array
*/
public function getJsConfig(): array
{
$config = $this->getLocaleInfo();
$negative = self::getAmountJsConfig($config['n_sep_by_space'], $config['n_sign_posn'], $config['negative_sign'], $config['n_cs_precedes']);
$positive = self::getAmountJsConfig($config['p_sep_by_space'], $config['p_sign_posn'], $config['positive_sign'], $config['p_cs_precedes']);
return [
'mon_decimal_point' => $config['mon_decimal_point'],
'mon_thousands_sep' => $config['mon_thousands_sep'],
'format' => [
'pos' => $positive,
'neg' => $negative,
'zero' => $positive,
],
];
}
/**
* @return array
*/
private function getLocaleInfo(): array
{
// get config from preference, not from translation:
$locale = app('steam')->getLocale();
$array = app('steam')->getLocaleArray($locale);
setlocale(LC_MONETARY, $array);
$info = localeconv();
// correct variables
$info['n_cs_precedes'] = $this->getLocaleField($info, 'n_cs_precedes');
$info['p_cs_precedes'] = $this->getLocaleField($info, 'p_cs_precedes');
$info['n_sep_by_space'] = $this->getLocaleField($info, 'n_sep_by_space');
$info['p_sep_by_space'] = $this->getLocaleField($info, 'p_sep_by_space');
$fmt = new NumberFormatter($locale, NumberFormatter::CURRENCY);
$info['mon_decimal_point'] = $fmt->getSymbol(NumberFormatter::MONETARY_SEPARATOR_SYMBOL);
$info['mon_thousands_sep'] = $fmt->getSymbol(NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL);
return $info;
}
/**
* @param array $info
* @param string $field
*
* @return bool
*/
private function getLocaleField(array $info, string $field): bool
{
return (is_bool($info[$field]) && true === $info[$field])
|| (is_int($info[$field]) && 1 === $info[$field]);
}
/**
* bool $sepBySpace is $localeconv['n_sep_by_space']
* int $signPosn = $localeconv['n_sign_posn']
@@ -111,230 +329,11 @@ class Amount
return $format;
}
/**
* This method returns the correct format rules required by accounting.js,
* the library used to format amounts in charts.
*
* Used only in one place.
*
* @return array
*/
public function getJsConfig(): array
{
$config = $this->getLocaleInfo();
$negative = self::getAmountJsConfig($config['n_sep_by_space'], $config['n_sign_posn'], $config['negative_sign'], $config['n_cs_precedes']);
$positive = self::getAmountJsConfig($config['p_sep_by_space'], $config['p_sign_posn'], $config['positive_sign'], $config['p_cs_precedes']);
return [
'mon_decimal_point' => $config['mon_decimal_point'],
'mon_thousands_sep' => $config['mon_thousands_sep'],
'format' => [
'pos' => $positive,
'neg' => $negative,
'zero' => $positive,
],
];
}
/**
* @return array
*/
private function getLocaleInfo(): array
{
// get config from preference, not from translation:
$locale = app('steam')->getLocale();
$array = app('steam')->getLocaleArray($locale);
setlocale(LC_MONETARY, $array);
$info = localeconv();
// correct variables
$info['n_cs_precedes'] = $this->getLocaleField($info, 'n_cs_precedes');
$info['p_cs_precedes'] = $this->getLocaleField($info, 'p_cs_precedes');
$info['n_sep_by_space'] = $this->getLocaleField($info, 'n_sep_by_space');
$info['p_sep_by_space'] = $this->getLocaleField($info, 'p_sep_by_space');
$fmt = new NumberFormatter( $locale, NumberFormatter::CURRENCY);
$info['mon_decimal_point'] = $fmt->getSymbol(NumberFormatter::MONETARY_SEPARATOR_SYMBOL);
$info['mon_thousands_sep'] = $fmt->getSymbol(NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL);
return $info;
}
/**
* This method will properly format the given number, in color or "black and white",
* as a currency, given two things: the currency required and the current locale.
*
* @param TransactionCurrency $format
* @param string $amount
* @param bool $coloured
*
* @return string
*
*/
public function formatAnything(TransactionCurrency $format, string $amount, bool $coloured = null): string
{
return $this->formatFlat($format->symbol, (int)$format->decimal_places, $amount, $coloured);
}
/**
* This method will properly format the given number, in color or "black and white",
* as a currency, given two things: the currency required and the current locale.
*
* @param string $symbol
* @param int $decimalPlaces
* @param string $amount
* @param bool $coloured
*
* @return string
*
* @noinspection MoreThanThreeArgumentsInspection
*/
public function formatFlat(string $symbol, int $decimalPlaces, string $amount, bool $coloured = null): string
{
$locale = app('steam')->getLocale();
$coloured = $coloured ?? true;
$fmt = new NumberFormatter( $locale, NumberFormatter::CURRENCY );
$fmt->setSymbol(NumberFormatter::CURRENCY_SYMBOL, $symbol);
$fmt->setAttribute(NumberFormatter::MIN_FRACTION_DIGITS, $decimalPlaces);
$fmt->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $decimalPlaces);
$result = $fmt->format((float) $amount);
if (true === $coloured) {
if ($amount > 0) {
return sprintf('<span class="text-success">%s</span>', $result);
}
if ($amount < 0) {
return sprintf('<span class="text-danger">%s</span>', $result);
}
return sprintf('<span style="color:#999">%s</span>', $result);
}
return $result;
}
/**
* @return Collection
*/
public function getAllCurrencies(): Collection
{
return TransactionCurrency::orderBy('code', 'ASC')->get();
}
/**
* @return Collection
*/
public function getCurrencies(): Collection
{
return TransactionCurrency::where('enabled', true)->orderBy('code', 'ASC')->get();
}
/**
* @return string
*/
public function getCurrencyCode(): string
{
$cache = new CacheProperties;
$cache->addProperty('getCurrencyCode');
if ($cache->has()) {
return $cache->get(); // @codeCoverageIgnore
}
$currencyPreference = app('preferences')->get('currencyPreference', config('firefly.default_currency', 'EUR'));
$currency = TransactionCurrency::where('code', $currencyPreference->data)->first();
if ($currency) {
$cache->store($currency->code);
return $currency->code;
}
$cache->store(config('firefly.default_currency', 'EUR'));
return (string)config('firefly.default_currency', 'EUR');
}
/**
* @return TransactionCurrency
*/
public function getDefaultCurrency(): TransactionCurrency
{
/** @var User $user */
$user = auth()->user();
return $this->getDefaultCurrencyByUser($user);
}
/**
* @return TransactionCurrency
*/
public function getSystemCurrency(): TransactionCurrency
{
return TransactionCurrency::where('code', 'EUR')->first();
}
/**
* @param User $user
*
* @return TransactionCurrency
*/
public function getDefaultCurrencyByUser(User $user): TransactionCurrency
{
$cache = new CacheProperties;
$cache->addProperty('getDefaultCurrency');
$cache->addProperty($user->id);
if ($cache->has()) {
return $cache->get(); // @codeCoverageIgnore
}
$currencyPreference = app('preferences')->getForUser($user, 'currencyPreference', config('firefly.default_currency', 'EUR'));
$currencyPrefStr = $currencyPreference ? $currencyPreference->data : 'EUR';
// at this point the currency preference could be encrypted, if coming from an old version.
$currencyCode = $this->tryDecrypt((string) $currencyPrefStr);
// could still be json encoded:
if (strlen($currencyCode) > 3) {
$currencyCode = json_decode($currencyCode, true, 512, JSON_THROW_ON_ERROR) ?? 'EUR';
}
/** @var TransactionCurrency $currency */
$currency = TransactionCurrency::where('code', $currencyCode)->first();
if (null === $currency) {
// get EUR
$currency = TransactionCurrency::where('code', 'EUR')->first();
}
$cache->store($currency);
return $currency;
}
/**
* @param array $info
* @param string $field
*
* @return bool
*/
private function getLocaleField(array $info, string $field): bool
{
return (is_bool($info[$field]) && true === $info[$field])
|| (is_int($info[$field]) && 1 === $info[$field]);
}
/**
* @param string $value
*
* @return string
*/
private function tryDecrypt(string $value): string
{
try {
$value = Crypt::decrypt($value); // verified
} catch (DecryptException $e) {
// ignore decryption error.
}
return $value;
return TransactionCurrency::where('code', 'EUR')->first();
}
}

View File

@@ -45,7 +45,7 @@ class RemoteUserGuard implements Guard
/**
* Create a new authentication guard.
*
* @param \Illuminate\Contracts\Auth\UserProvider $provider
* @param UserProvider $provider
*
* @return void
*/
@@ -79,10 +79,10 @@ class RemoteUserGuard implements Guard
$retrievedUser = $this->provider->retrieveById($userID);
// store email address if present in header and not already set.
$header = config('auth.guard_email');
$header = config('auth.guard_email');
if (null !== $header) {
$emailAddress = (string) (request()->server($header) ?? null);
$emailAddress = (string)(request()->server($header) ?? null);
$preference = app('preferences')->getForUser($retrievedUser, 'remote_guard_alt_email', null);
if (null !== $emailAddress && null === $preference && $emailAddress !== $userID) {

View File

@@ -39,7 +39,7 @@ class Date implements BinderInterface
* @param Route $route
*
* @return Carbon
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
* @throws NotFoundHttpException
*/
public static function routeBinder(string $value, Route $route): Carbon
{

View File

@@ -39,7 +39,7 @@ class TagList implements BinderInterface
* @param Route $route
*
* @return Collection
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
* @throws NotFoundHttpException
*/
public static function routeBinder(string $value, Route $route): Collection
{

View File

@@ -23,10 +23,13 @@ declare(strict_types=1);
namespace FireflyIII\Support;
use Cache;
use Carbon\Carbon;
use FireflyIII\Models\Category;
use Illuminate\Support\Collection;
/**
* Class CacheProperties.
*
* @codeCoverageIgnore
*/
class CacheProperties
@@ -49,8 +52,8 @@ class CacheProperties
}
/**
* @param $property
* @param Collection|\Carbon\Carbon|\FireflyIII\Models\Category|array|int|string $property
* @param $property
* @param Collection|Carbon|Category|array|int|string $property
*/
public function addProperty($property): void
{
@@ -86,15 +89,6 @@ class CacheProperties
return Cache::has($this->hash);
}
/**
* @param $data
* @param (array|mixed)[]|Collection|\Carbon\Carbon|string $data
*/
public function store($data): void
{
Cache::forever($this->hash, $data);
}
/**
*/
private function hash(): void
@@ -105,4 +99,13 @@ class CacheProperties
}
$this->hash = substr(hash('sha256', $content), 0, 16);
}
/**
* @param $data
* @param (array|mixed)[]|Collection|\Carbon\Carbon|string $data
*/
public function store($data): void
{
Cache::forever($this->hash, $data);
}
}

View File

@@ -37,13 +37,13 @@ use Illuminate\Support\Collection;
*/
class FrontpageChartGenerator
{
private User $user;
private Carbon $start;
private Carbon $end;
private BudgetRepositoryInterface $budgetRepository;
private BudgetLimitRepositoryInterface $blRepository;
protected OperationsRepositoryInterface $opsRepository;
private BudgetLimitRepositoryInterface $blRepository;
private BudgetRepositoryInterface $budgetRepository;
private Carbon $end;
private string $monthAndDayFormat;
private Carbon $start;
private User $user;
/**
* FrontpageChartGenerator constructor.
@@ -79,38 +79,6 @@ class FrontpageChartGenerator
return $data;
}
/**
* A basic setter for the user. Also updates the repositories with the right user.
*
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
$this->budgetRepository->setUser($user);
$this->blRepository->setUser($user);
$this->opsRepository->setUser($user);
$locale = app('steam')->getLocale();
$this->monthAndDayFormat = (string)trans('config.month_and_day', [], $locale);
}
/**
* @param Carbon $start
*/
public function setStart(Carbon $start): void
{
$this->start = $start;
}
/**
* @param Carbon $end
*/
public function setEnd(Carbon $end): void
{
$this->end = $end;
}
/**
* For each budget, gets all budget limits for the current time range.
* When no limits are present, the time range is used to collect information on money spent.
@@ -238,5 +206,37 @@ class FrontpageChartGenerator
return $data;
}
/**
* @param Carbon $end
*/
public function setEnd(Carbon $end): void
{
$this->end = $end;
}
/**
* @param Carbon $start
*/
public function setStart(Carbon $start): void
{
$this->start = $start;
}
/**
* A basic setter for the user. Also updates the repositories with the right user.
*
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
$this->budgetRepository->setUser($user);
$this->blRepository->setUser($user);
$this->opsRepository->setUser($user);
$locale = app('steam')->getLocale();
$this->monthAndDayFormat = (string)trans('config.month_and_day', [], $locale);
}
}

View File

@@ -99,6 +99,29 @@ class FrontpageChartGenerator
return $this->insertValues($currencyData, $tempData);
}
/**
* @param Category $category
* @param Collection $accounts
*
* @return array
*/
private function collectExpenses(Category $category, Collection $accounts): array
{
$spent = $this->opsRepos->sumExpenses($this->start, $this->end, $accounts, new Collection([$category]));
$tempData = [];
foreach ($spent as $currency) {
$this->addCurrency($currency);
$tempData[] = [
'name' => $category->name,
'sum' => $currency['sum'],
'sum_float' => round((float)$currency['sum'], $currency['currency_decimal_places']),
'currency_id' => (int)$currency['currency_id'],
];
}
return $tempData;
}
/**
* @param array $currency
*/
@@ -115,29 +138,6 @@ class FrontpageChartGenerator
];
}
/**
* @param Category $category
* @param Collection $accounts
*
* @return array
*/
private function collectExpenses(Category $category, Collection $accounts): array
{
$spent = $this->opsRepos->sumExpenses($this->start, $this->end, $accounts, new Collection([$category]));
$tempData = [];
foreach ($spent as $currency) {
$this->addCurrency($currency);
$tempData[] = [
'name' => $category->name,
'sum' => $currency['sum'],
'sum_float' => round((float) $currency['sum'], $currency['currency_decimal_places']),
'currency_id' => (int)$currency['currency_id'],
];
}
return $tempData;
}
/**
* @param Collection $accounts
*
@@ -152,7 +152,7 @@ class FrontpageChartGenerator
$tempData[] = [
'name' => trans('firefly.no_category'),
'sum' => $currency['sum'],
'sum_float' => round((float) $currency['sum'], $currency['currency_decimal_places'] ?? 2),
'sum_float' => round((float)$currency['sum'], $currency['currency_decimal_places'] ?? 2),
'currency_id' => (int)$currency['currency_id'],
];
}

View File

@@ -27,10 +27,8 @@ use Carbon\Carbon;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\Category\OperationsRepositoryInterface;
use Illuminate\Support\Collection;
use Log;
/**
* Class WholePeriodChartGenerator
@@ -109,8 +107,8 @@ class WholePeriodChartGenerator
$earnedInfoKey = sprintf('earned-in-%s', $code);
$spentAmount = $spent[$key][$currencyId]['sum'] ?? '0';
$earnedAmount = $earned[$key][$currencyId]['sum'] ?? '0';
$chartData[$spentInfoKey]['entries'][$label] = round((float) $spentAmount, $currency['currency_decimal_places']);
$chartData[$earnedInfoKey]['entries'][$label] = round((float) $earnedAmount, $currency['currency_decimal_places']);
$chartData[$spentInfoKey]['entries'][$label] = round((float)$spentAmount, $currency['currency_decimal_places']);
$chartData[$earnedInfoKey]['entries'][$label] = round((float)$earnedAmount, $currency['currency_decimal_places']);
}
$current = app('navigation')->addPeriod($current, $step, 0);
}

View File

@@ -24,6 +24,7 @@ namespace FireflyIII\Support;
/**
* Class ChartColour.
*
* @codeCoverageIgnore
*/
class ChartColour

View File

@@ -25,6 +25,7 @@ namespace FireflyIII\Support\Cronjobs;
use Carbon\Carbon;
use Exception;
/**
* Class AbstractCronjob
*
@@ -34,12 +35,10 @@ abstract class AbstractCronjob
{
/** @var int */
public $timeBetweenRuns = 43200;
/** @var bool */
protected $force;
/** @var Carbon */
protected $date;
/** @var bool */
protected $force;
/**
* AbstractCronjob constructor.
@@ -52,15 +51,10 @@ abstract class AbstractCronjob
$this->date = today(config('app.timezone'));
}
/**
* @param bool $force
* @return bool
*/
public function setForce(bool $force): void
{
$this->force = $force;
}
abstract public function fire(): bool;
/**
* @param Carbon $date
@@ -71,8 +65,11 @@ abstract class AbstractCronjob
}
/**
* @return bool
* @param bool $force
*/
abstract public function fire(): bool;
public function setForce(bool $force): void
{
$this->force = $force;
}
}

View File

@@ -86,7 +86,7 @@ class RecurringCronjob extends AbstractCronjob
$job->setForce($this->force);
$job->handle();
app('fireflyconfig')->set('last_rt_job', (int)$this->date->format('U'));
Log::info(sprintf('Marked the last time this job has run as "%s" (%d)',$this->date->format('Y-m-d H:i:s'),(int)$this->date->format('U')));
Log::info(sprintf('Marked the last time this job has run as "%s" (%d)', $this->date->format('Y-m-d H:i:s'), (int)$this->date->format('U')));
Log::info('Done with recurring cron job task.');
}
}

View File

@@ -45,13 +45,14 @@ class TelemetryCronjob extends AbstractCronjob
// do not fire if telemetry is disabled.
if (false === config('firefly.send_telemetry') || false === config('firefly.feature_flags.telemetry')) {
Log::warning('Telemetry is disabled. The cron job will do nothing.');
return false;
}
/** @var Configuration $config */
$config = app('fireflyconfig')->get('last_tm_job', 0);
$lastTime = (int) $config->data;
$lastTime = (int)$config->data;
$diff = time() - $lastTime;
$diffForHumans = Carbon::now()->diffForHumans(Carbon::createFromTimestamp($lastTime), true);
if (0 === $lastTime) {
@@ -98,7 +99,7 @@ class TelemetryCronjob extends AbstractCronjob
// TODO remove old, submitted telemetry data.
app('fireflyconfig')->set('last_tm_job', (int) $this->date->format('U'));
app('fireflyconfig')->set('last_tm_job', (int)$this->date->format('U'));
Log::info('Done with telemetry cron job task.');
}
}

View File

@@ -24,6 +24,7 @@ namespace FireflyIII\Support;
/**
* Class Domain.
*
* @codeCoverageIgnore
*/
class Domain

View File

@@ -39,10 +39,11 @@ use Throwable;
class ExpandedForm
{
use FormSupport;
/**
* @param string $name
* @param mixed $value
* @param array $options
* @param mixed $value
* @param array $options
*
* @return string
*
@@ -59,7 +60,7 @@ class ExpandedForm
// make sure value is formatted nicely:
if (null !== $value && '' !== $value) {
$value = round((float) $value, 8);
$value = round((float)$value, 8);
}
try {
$html = prefixView('form.amount-no-currency', compact('classes', 'name', 'label', 'value', 'options'))->render();
@@ -73,9 +74,9 @@ class ExpandedForm
/**
* @param string $name
* @param int $value
* @param mixed $checked
* @param array $options
* @param int $value
* @param mixed $checked
* @param array $options
*
* @return string
*
@@ -109,8 +110,8 @@ class ExpandedForm
/**
* @param string $name
* @param mixed $value
* @param array $options
* @param mixed $value
* @param array $options
*
* @return string
*
@@ -134,7 +135,7 @@ class ExpandedForm
/**
* @param string $name
* @param array $options
* @param array $options
*
* @return string
*
@@ -157,8 +158,8 @@ class ExpandedForm
/**
* @param string $name
* @param mixed $value
* @param array $options
* @param mixed $value
* @param array $options
*
* @return string
*
@@ -183,8 +184,8 @@ class ExpandedForm
/**
* @param string $name
* @param mixed $value
* @param array $options
* @param mixed $value
* @param array $options
*
* @return string
*
@@ -207,7 +208,7 @@ class ExpandedForm
}
/**
* @param \Illuminate\Support\Collection $set
* @param Collection $set
*
* @return array
*
@@ -235,8 +236,8 @@ class ExpandedForm
/**
* @param string $name
* @param mixed $value
* @param array $options
* @param mixed $value
* @param array $options
*
* @return string
*/
@@ -252,7 +253,7 @@ class ExpandedForm
// make sure value is formatted nicely:
if (null !== $value && '' !== $value) {
$value = round((float) $value, $selectedCurrency->decimal_places);
$value = round((float)$value, $selectedCurrency->decimal_places);
}
try {
$html = prefixView('form.non-selectable-amount', compact('selectedCurrency', 'classes', 'name', 'label', 'value', 'options'))->render();
@@ -266,8 +267,8 @@ class ExpandedForm
/**
* @param string $name
* @param mixed $value
* @param array $options
* @param mixed $value
* @param array $options
*
* @return string
*
@@ -290,153 +291,6 @@ class ExpandedForm
return $html;
}
/**
* @param string $type
* @param string $name
*
* @return string
*
*/
public function optionsList(string $type, string $name): string
{
try {
$html = prefixView('form.options', compact('type', 'name'))->render();
} catch (Throwable $e) {
Log::debug(sprintf('Could not render select(): %s', $e->getMessage()));
$html = 'Could not render optionsList.';
}
return $html;
}
/**
* @param string $name
* @param array $options
*
* @return string
*
*/
public function password(string $name, array $options = null): string
{
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
try {
$html = prefixView('form.password', compact('classes', 'name', 'label', 'options'))->render();
} catch (Throwable $e) {
Log::debug(sprintf('Could not render password(): %s', $e->getMessage()));
$html = 'Could not render password.';
}
return $html;
}
/**
* Function to render a percentage.
*
* @param string $name
* @param mixed $value
* @param array $options
*
* @return string
*
*/
public function percentage(string $name, $value = null, array $options = null): string
{
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value);
$options['step'] = 'any';
unset($options['placeholder']);
try {
$html = prefixView('form.percentage', compact('classes', 'name', 'label', 'value', 'options'))->render();
} catch (Throwable $e) {
Log::debug(sprintf('Could not render percentage(): %s', $e->getMessage()));
$html = 'Could not render percentage.';
}
return $html;
}
/**
* @param string $name
* @param mixed $value
* @param array $options
*
* @return string
*
*/
public function staticText(string $name, $value, array $options = null): string
{
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
try {
$html = prefixView('form.static', compact('classes', 'name', 'label', 'value', 'options'))->render();
} catch (Throwable $e) {
Log::debug(sprintf('Could not render staticText(): %s', $e->getMessage()));
$html = 'Could not render staticText.';
}
return $html;
}
/**
* @param string $name
* @param mixed $value
* @param array $options
*
* @return string
*
*/
public function text(string $name, $value = null, array $options = null): string
{
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value);
try {
$html = prefixView('form.text', compact('classes', 'name', 'label', 'value', 'options'))->render();
} catch (Throwable $e) {
Log::debug(sprintf('Could not render text(): %s', $e->getMessage()));
$html = 'Could not render text.';
}
return $html;
}
/**
* @param string $name
* @param mixed $value
* @param array $options
*
* @return string
*
*/
public function textarea(string $name, $value = null, array $options = null): string
{
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value);
$options['rows'] = 4;
if (null === $value) {
$value = '';
}
try {
$html = prefixView('form.textarea', compact('classes', 'name', 'label', 'value', 'options'))->render();
} catch (Throwable $e) {
Log::debug(sprintf('Could not render textarea(): %s', $e->getMessage()));
$html = 'Could not render textarea.';
}
return $html;
}
/**
* @param null $value
* @param array|null $options
@@ -465,4 +319,151 @@ class ExpandedForm
return $html;
}
/**
* @param string $type
* @param string $name
*
* @return string
*
*/
public function optionsList(string $type, string $name): string
{
try {
$html = prefixView('form.options', compact('type', 'name'))->render();
} catch (Throwable $e) {
Log::debug(sprintf('Could not render select(): %s', $e->getMessage()));
$html = 'Could not render optionsList.';
}
return $html;
}
/**
* @param string $name
* @param array $options
*
* @return string
*
*/
public function password(string $name, array $options = null): string
{
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
try {
$html = prefixView('form.password', compact('classes', 'name', 'label', 'options'))->render();
} catch (Throwable $e) {
Log::debug(sprintf('Could not render password(): %s', $e->getMessage()));
$html = 'Could not render password.';
}
return $html;
}
/**
* Function to render a percentage.
*
* @param string $name
* @param mixed $value
* @param array $options
*
* @return string
*
*/
public function percentage(string $name, $value = null, array $options = null): string
{
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value);
$options['step'] = 'any';
unset($options['placeholder']);
try {
$html = prefixView('form.percentage', compact('classes', 'name', 'label', 'value', 'options'))->render();
} catch (Throwable $e) {
Log::debug(sprintf('Could not render percentage(): %s', $e->getMessage()));
$html = 'Could not render percentage.';
}
return $html;
}
/**
* @param string $name
* @param mixed $value
* @param array $options
*
* @return string
*
*/
public function staticText(string $name, $value, array $options = null): string
{
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
try {
$html = prefixView('form.static', compact('classes', 'name', 'label', 'value', 'options'))->render();
} catch (Throwable $e) {
Log::debug(sprintf('Could not render staticText(): %s', $e->getMessage()));
$html = 'Could not render staticText.';
}
return $html;
}
/**
* @param string $name
* @param mixed $value
* @param array $options
*
* @return string
*
*/
public function text(string $name, $value = null, array $options = null): string
{
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value);
try {
$html = prefixView('form.text', compact('classes', 'name', 'label', 'value', 'options'))->render();
} catch (Throwable $e) {
Log::debug(sprintf('Could not render text(): %s', $e->getMessage()));
$html = 'Could not render text.';
}
return $html;
}
/**
* @param string $name
* @param mixed $value
* @param array $options
*
* @return string
*
*/
public function textarea(string $name, $value = null, array $options = null): string
{
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value);
$options['rows'] = 4;
if (null === $value) {
$value = '';
}
try {
$html = prefixView('form.textarea', compact('classes', 'name', 'label', 'value', 'options'))->render();
} catch (Throwable $e) {
Log::debug(sprintf('Could not render textarea(): %s', $e->getMessage()));
$html = 'Could not render textarea.';
}
return $html;
}
}

View File

@@ -51,6 +51,7 @@ use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
use FireflyIII\User;
use Illuminate\Support\Collection;
use League\Csv\CannotInsertRecord;
use League\Csv\Writer;
/**
@@ -58,19 +59,19 @@ use League\Csv\Writer;
*/
class ExportDataGenerator
{
private Collection $accounts;
private Carbon $end;
private bool $exportTransactions;
private Carbon $start;
private bool $exportAccounts;
private bool $exportBills;
private bool $exportBudgets;
private bool $exportCategories;
private bool $exportTags;
private bool $exportPiggies;
private bool $exportRecurring;
private bool $exportRules;
private bool $exportBills;
private bool $exportPiggies;
private bool $exportTags;
private bool $exportTransactions;
private Carbon $start;
private User $user;
private Collection $accounts;
public function __construct()
{
@@ -89,25 +90,9 @@ class ExportDataGenerator
$this->exportPiggies = false;
}
/**
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
}
/**
* @param Collection $accounts
*/
public function setAccounts(Collection $accounts): void
{
$this->accounts = $accounts;
}
/**
* @return array
* @throws \League\Csv\CannotInsertRecord
* @throws CannotInsertRecord
*/
public function export(): array
{
@@ -143,150 +128,6 @@ class ExportDataGenerator
return $return;
}
/**
* @param bool $exportAccounts
*/
public function setExportAccounts(bool $exportAccounts): void
{
$this->exportAccounts = $exportAccounts;
}
/**
* @param bool $exportBudgets
*/
public function setExportBudgets(bool $exportBudgets): void
{
$this->exportBudgets = $exportBudgets;
}
/**
* @param bool $exportCategories
*/
public function setExportCategories(bool $exportCategories): void
{
$this->exportCategories = $exportCategories;
}
/**
* @param bool $exportTags
*/
public function setExportTags(bool $exportTags): void
{
$this->exportTags = $exportTags;
}
/**
* @param bool $exportRecurring
*/
public function setExportRecurring(bool $exportRecurring): void
{
$this->exportRecurring = $exportRecurring;
}
/**
* @param bool $exportRules
*/
public function setExportRules(bool $exportRules): void
{
$this->exportRules = $exportRules;
}
/**
* @param bool $exportBills
*/
public function setExportBills(bool $exportBills): void
{
$this->exportBills = $exportBills;
}
/**
* @param bool $exportPiggies
*/
public function setExportPiggies(bool $exportPiggies): void
{
$this->exportPiggies = $exportPiggies;
}
/**
* @param Carbon $end
*/
public function setEnd(Carbon $end): void
{
$this->end = $end;
}
/**
* @param bool $exportTransactions
*/
public function setExportTransactions(bool $exportTransactions): void
{
$this->exportTransactions = $exportTransactions;
}
/**
* @param Carbon $start
*/
public function setStart(Carbon $start): void
{
$this->start = $start;
}
/**
* @return string
*/
private function exportRules(): string
{
$header = ['user_id', 'rule_id', 'row_contains', 'created_at', 'updated_at', 'group_id', 'group_name', 'title', 'description', 'order', 'active',
'stop_processing', 'strict', 'trigger_type', 'trigger_value', 'trigger_order', 'trigger_active', 'trigger_stop_processing', 'action_type',
'action_value', 'action_order', 'action_active', 'action_stop_processing',];
$ruleRepos = app(RuleRepositoryInterface::class);
$ruleRepos->setUser($this->user);
$rules = $ruleRepos->getAll();
$records = [];
/** @var Rule $rule */
foreach ($rules as $rule) {
$records[] = [
$this->user->id, $rule->id, 'rule',
$rule->created_at->toAtomString(), $rule->updated_at->toAtomString(),
$rule->ruleGroup->id, $rule->ruleGroup->name,
$rule->title, $rule->description, $rule->order, $rule->active, $rule->stop_processing, $rule->strict,
];
/** @var RuleTrigger $trigger */
foreach ($rule->ruleTriggers as $trigger) {
$records[] = [
$this->user->id, $rule->id, 'trigger',
null, null,
null, null,
null, null, null, null, null, null,
$trigger->trigger_type, $trigger->trigger_value, $trigger->order, $trigger->active, $trigger->stop_processing,
];
}
/** @var RuleAction $action */
foreach ($rule->ruleActions as $action) {
$records[] = [
$this->user->id, $rule->id, 'action',
null, null,
null, null,
null, null, null, null, null, null,
null, null, null, null, null,
$action->action_type, $action->action_value, $action->order, $action->active, $action->stop_processing,
];
}
}
//load the CSV document from a string
$csv = Writer::createFromString('');
//insert the header
$csv->insertOne($header);
//insert all the records
$csv->insertAll($records);
return $csv->getContent(); //returns the CSV document as a string
}
/**
* @return string
*/
@@ -380,7 +221,7 @@ class ExportDataGenerator
/**
* @return string
* @throws \League\Csv\CannotInsertRecord
* @throws CannotInsertRecord
*/
private function exportBudgets(): string
{
@@ -610,6 +451,62 @@ class ExportDataGenerator
return $csv->getContent(); //returns the CSV document as a string
}
/**
* @return string
*/
private function exportRules(): string
{
$header = ['user_id', 'rule_id', 'row_contains', 'created_at', 'updated_at', 'group_id', 'group_name', 'title', 'description', 'order', 'active',
'stop_processing', 'strict', 'trigger_type', 'trigger_value', 'trigger_order', 'trigger_active', 'trigger_stop_processing', 'action_type',
'action_value', 'action_order', 'action_active', 'action_stop_processing',];
$ruleRepos = app(RuleRepositoryInterface::class);
$ruleRepos->setUser($this->user);
$rules = $ruleRepos->getAll();
$records = [];
/** @var Rule $rule */
foreach ($rules as $rule) {
$records[] = [
$this->user->id, $rule->id, 'rule',
$rule->created_at->toAtomString(), $rule->updated_at->toAtomString(),
$rule->ruleGroup->id, $rule->ruleGroup->name,
$rule->title, $rule->description, $rule->order, $rule->active, $rule->stop_processing, $rule->strict,
];
/** @var RuleTrigger $trigger */
foreach ($rule->ruleTriggers as $trigger) {
$records[] = [
$this->user->id, $rule->id, 'trigger',
null, null,
null, null,
null, null, null, null, null, null,
$trigger->trigger_type, $trigger->trigger_value, $trigger->order, $trigger->active, $trigger->stop_processing,
];
}
/** @var RuleAction $action */
foreach ($rule->ruleActions as $action) {
$records[] = [
$this->user->id, $rule->id, 'action',
null, null,
null, null,
null, null, null, null, null, null,
null, null, null, null, null,
$action->action_type, $action->action_value, $action->order, $action->active, $action->stop_processing,
];
}
}
//load the CSV document from a string
$csv = Writer::createFromString('');
//insert the header
$csv->insertOne($header);
//insert all the records
$csv->insertAll($records);
return $csv->getContent(); //returns the CSV document as a string
}
/**
* @return string
*/
@@ -668,7 +565,7 @@ class ExportDataGenerator
$collector->setUser($this->user);
$collector->setRange($this->start, $this->end)->withAccountInformation()->withCategoryInformation()->withBillInformation()
->withBudgetInformation()->withTagInformation()->withNotes();
if(0 !== $this->accounts->count()) {
if (0 !== $this->accounts->count()) {
$collector->setAccounts($this->accounts);
}
@@ -776,4 +673,108 @@ class ExportDataGenerator
return implode(',', $smol);
}
/**
* @param Collection $accounts
*/
public function setAccounts(Collection $accounts): void
{
$this->accounts = $accounts;
}
/**
* @param Carbon $end
*/
public function setEnd(Carbon $end): void
{
$this->end = $end;
}
/**
* @param bool $exportAccounts
*/
public function setExportAccounts(bool $exportAccounts): void
{
$this->exportAccounts = $exportAccounts;
}
/**
* @param bool $exportBills
*/
public function setExportBills(bool $exportBills): void
{
$this->exportBills = $exportBills;
}
/**
* @param bool $exportBudgets
*/
public function setExportBudgets(bool $exportBudgets): void
{
$this->exportBudgets = $exportBudgets;
}
/**
* @param bool $exportCategories
*/
public function setExportCategories(bool $exportCategories): void
{
$this->exportCategories = $exportCategories;
}
/**
* @param bool $exportPiggies
*/
public function setExportPiggies(bool $exportPiggies): void
{
$this->exportPiggies = $exportPiggies;
}
/**
* @param bool $exportRecurring
*/
public function setExportRecurring(bool $exportRecurring): void
{
$this->exportRecurring = $exportRecurring;
}
/**
* @param bool $exportRules
*/
public function setExportRules(bool $exportRules): void
{
$this->exportRules = $exportRules;
}
/**
* @param bool $exportTags
*/
public function setExportTags(bool $exportTags): void
{
$this->exportTags = $exportTags;
}
/**
* @param bool $exportTransactions
*/
public function setExportTransactions(bool $exportTransactions): void
{
$this->exportTransactions = $exportTransactions;
}
/**
* @param Carbon $start
*/
public function setStart(Carbon $start): void
{
$this->start = $start;
}
/**
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
}
}

View File

@@ -27,6 +27,7 @@ use FireflyIII\User;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Facade;
use Log;
/**
* @codeCoverageIgnore
* Class Preferences.

View File

@@ -31,6 +31,7 @@ use Log;
/**
* Class FireflyConfig.
*
* @codeCoverageIgnore
*/
class FireflyConfig
@@ -67,8 +68,8 @@ class FireflyConfig
* @param string $name
* @param null $default
*
* @throws FireflyException
* @return Configuration|null
* @throws FireflyException
*/
public function get(string $name, $default = null): ?Configuration
{
@@ -80,7 +81,7 @@ class FireflyConfig
try {
/** @var Configuration $config */
$config = Configuration::where('name', $name)->first(['id', 'name', 'data']);
} catch (QueryException|Exception $e) {
} catch (QueryException | Exception $e) {
throw new FireflyException(sprintf('Could not poll the database: %s', $e->getMessage()));
}
@@ -99,7 +100,7 @@ class FireflyConfig
/**
* @param string $name
* @param mixed $default
* @param mixed $default
*
* @return \FireflyIII\Models\Configuration|null
*/
@@ -132,8 +133,8 @@ class FireflyConfig
}
/**
* @param string $name
* @param $value
* @param string $name
* @param $value
* @param int|string|true $value
*
* @return Configuration
@@ -143,7 +144,7 @@ class FireflyConfig
/** @var Configuration $config */
try {
$config = Configuration::whereName($name)->first();
} catch (QueryException|Exception $e) {
} catch (QueryException | Exception $e) {
$item = new Configuration;
$item->name = $name;
$item->data = $value;

View File

@@ -42,18 +42,39 @@ class AccountForm
{
use FormSupport;
/**
* Grouped dropdown list of all accounts that are valid as the destination of a withdrawal.
*
* @param string $name
* @param mixed $value
* @param array $options
*
* @return string
*/
public function activeDepositDestinations(string $name, $value = null, array $options = null): string
{
$types = [AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN, AccountType::REVENUE,];
$repository = $this->getAccountRepository();
$grouped = $this->getAccountsGrouped($types, $repository);
$cash = $repository->getCashAccount();
$key = (string)trans('firefly.cash_account_type');
$grouped[$key][$cash->id] = sprintf('(%s)', (string)trans('firefly.cash'));
return $this->select($name, $grouped, $value, $options);
}
private function getAccountsGrouped(array $types, AccountRepositoryInterface $repository = null): array
{
if (null === $repository) {
$repository = $this->getAccountRepository();
}
$accountList = $repository->getActiveAccountsByType($types);
$liabilityTypes = [AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN,];
$grouped = [];
$accountList = $repository->getActiveAccountsByType($types);
$liabilityTypes = [AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN,];
$grouped = [];
/** @var Account $account */
foreach ($accountList as $account) {
$role = (string)$repository->getMetaValue($account, 'account_role');
$role = (string)$repository->getMetaValue($account, 'account_role');
if (in_array($account->accountType->type, $liabilityTypes, true)) {
$role = sprintf('l_%s', $account->accountType->type);
} elseif ('' === $role) {
@@ -65,7 +86,7 @@ class AccountForm
$role = 'no_account_type';
}
}
$key = (string) trans(sprintf('firefly.opt_group_%s', $role));
$key = (string)trans(sprintf('firefly.opt_group_%s', $role));
$grouped[$key][$account->id] = $account->name;
}
@@ -76,8 +97,8 @@ class AccountForm
* Grouped dropdown list of all accounts that are valid as the destination of a withdrawal.
*
* @param string $name
* @param mixed $value
* @param array $options
* @param mixed $value
* @param array $options
*
* @return string
*/
@@ -94,33 +115,11 @@ class AccountForm
return $this->select($name, $grouped, $value, $options);
}
/**
* Grouped dropdown list of all accounts that are valid as the destination of a withdrawal.
*
* @param string $name
* @param mixed $value
* @param array $options
*
* @return string
*/
public function activeDepositDestinations(string $name, $value = null, array $options = null): string
{
$types = [AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN, AccountType::REVENUE,];
$repository = $this->getAccountRepository();
$grouped = $this->getAccountsGrouped($types, $repository);
$cash = $repository->getCashAccount();
$key = (string)trans('firefly.cash_account_type');
$grouped[$key][$cash->id] = sprintf('(%s)', (string)trans('firefly.cash'));
return $this->select($name, $grouped, $value, $options);
}
/**
* Check list of asset accounts.
*
* @param string $name
* @param array $options
* @param array $options
*
* @return string
*
@@ -134,8 +133,8 @@ class AccountForm
$selected = request()->old($name) ?? [];
// get all asset accounts:
$types = [AccountType::ASSET, AccountType::DEFAULT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::DEBT];
$grouped = $this->getAccountsGrouped($types);
$types = [AccountType::ASSET, AccountType::DEFAULT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::DEBT];
$grouped = $this->getAccountsGrouped($types);
unset($options['class']);
try {
@@ -152,8 +151,8 @@ class AccountForm
* Basic list of asset accounts.
*
* @param string $name
* @param mixed $value
* @param array $options
* @param mixed $value
* @param array $options
*
* @return string
*/
@@ -170,8 +169,8 @@ class AccountForm
* Same list but all liabilities as well.
*
* @param string $name
* @param mixed $value
* @param array $options
* @param mixed $value
* @param array $options
*
* @return string
*/

View File

@@ -44,56 +44,67 @@ class CurrencyForm
use FormSupport;
/**
* TODO cleanup and describe.
* @param string $name
* @param mixed $value
* @param array $options
*
* @return string
*/
public function currencyList(string $name, $value = null, array $options = null): string
public function amount(string $name, $value = null, array $options = null): string
{
/** @var CurrencyRepositoryInterface $currencyRepos */
$currencyRepos = app(CurrencyRepositoryInterface::class);
// get all currencies:
$list = $currencyRepos->get();
$array = [];
/** @var TransactionCurrency $currency */
foreach ($list as $currency) {
$array[$currency->id] = $currency->name . ' (' . $currency->symbol . ')';
}
return $this->select($name, $array, $value, $options);
return $this->currencyField($name, 'amount', $value, $options);
}
/**
* TODO cleanup and describe.
*
* @param string $name
* @param string $view
* @param mixed $value
* @param array $options
*
* @return string
*
*/
public function currencyListEmpty(string $name, $value = null, array $options = null): string
protected function currencyField(string $name, string $view, $value = null, array $options = null): string
{
/** @var CurrencyRepositoryInterface $currencyRepos */
$currencyRepos = app(CurrencyRepositoryInterface::class);
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value);
$options['step'] = 'any';
$defaultCurrency = $options['currency'] ?? Amt::getDefaultCurrency();
/** @var Collection $currencies */
$currencies = app('amount')->getCurrencies();
unset($options['currency'], $options['placeholder']);
// get all currencies:
$list = $currencyRepos->get();
$array = [
0 => (string)trans('firefly.no_currency'),
];
/** @var TransactionCurrency $currency */
foreach ($list as $currency) {
$array[$currency->id] = $currency->name . ' (' . $currency->symbol . ')';
// perhaps the currency has been sent to us in the field $amount_currency_id_$name (amount_currency_id_amount)
$preFilled = session('preFilled');
$key = 'amount_currency_id_' . $name;
$sentCurrencyId = isset($preFilled[$key]) ? (int)$preFilled[$key] : $defaultCurrency->id;
Log::debug(sprintf('Sent currency ID is %d', $sentCurrencyId));
// find this currency in set of currencies:
foreach ($currencies as $currency) {
if ($currency->id === $sentCurrencyId) {
$defaultCurrency = $currency;
Log::debug(sprintf('default currency is now %s', $defaultCurrency->code));
break;
}
}
return $this->select($name, $array, $value, $options);
}
// make sure value is formatted nicely:
if (null !== $value && '' !== $value) {
$value = round((float)$value, $defaultCurrency->decimal_places);
}
try {
$html = prefixView('form.' . $view, compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render();
} catch (Throwable $e) {
Log::debug(sprintf('Could not render currencyField(): %s', $e->getMessage()));
$html = 'Could not render currencyField.';
}
return $html;
}
/**
* TODO describe and cleanup.
@@ -151,7 +162,7 @@ class CurrencyForm
// make sure value is formatted nicely:
if (null !== $value && '' !== $value) {
$value = round((float) $value, $defaultCurrency->decimal_places);
$value = round((float)$value, $defaultCurrency->decimal_places);
}
try {
$html = prefixView('form.' . $view, compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render();
@@ -164,66 +175,55 @@ class CurrencyForm
}
/**
* TODO cleanup and describe.
*
* @param string $name
* @param string $view
* @param mixed $value
* @param array $options
*
* @return string
*
*/
protected function currencyField(string $name, string $view, $value = null, array $options = null): string
public function currencyList(string $name, $value = null, array $options = null): string
{
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value);
$options['step'] = 'any';
$defaultCurrency = $options['currency'] ?? Amt::getDefaultCurrency();
/** @var Collection $currencies */
$currencies = app('amount')->getCurrencies();
unset($options['currency'], $options['placeholder']);
/** @var CurrencyRepositoryInterface $currencyRepos */
$currencyRepos = app(CurrencyRepositoryInterface::class);
// perhaps the currency has been sent to us in the field $amount_currency_id_$name (amount_currency_id_amount)
$preFilled = session('preFilled');
$key = 'amount_currency_id_' . $name;
$sentCurrencyId = isset($preFilled[$key]) ? (int)$preFilled[$key] : $defaultCurrency->id;
Log::debug(sprintf('Sent currency ID is %d', $sentCurrencyId));
// find this currency in set of currencies:
foreach ($currencies as $currency) {
if ($currency->id === $sentCurrencyId) {
$defaultCurrency = $currency;
Log::debug(sprintf('default currency is now %s', $defaultCurrency->code));
break;
}
// get all currencies:
$list = $currencyRepos->get();
$array = [];
/** @var TransactionCurrency $currency */
foreach ($list as $currency) {
$array[$currency->id] = $currency->name . ' (' . $currency->symbol . ')';
}
// make sure value is formatted nicely:
if (null !== $value && '' !== $value) {
$value = round((float) $value, $defaultCurrency->decimal_places);
}
try {
$html = prefixView('form.' . $view, compact('defaultCurrency', 'currencies', 'classes', 'name', 'label', 'value', 'options'))->render();
} catch (Throwable $e) {
Log::debug(sprintf('Could not render currencyField(): %s', $e->getMessage()));
$html = 'Could not render currencyField.';
}
return $html;
return $this->select($name, $array, $value, $options);
}
/**
* TODO cleanup and describe.
*
* @param string $name
* @param mixed $value
* @param array $options
* @param mixed $value
* @param array $options
*
* @return string
*/
public function amount(string $name, $value = null, array $options = null): string
public function currencyListEmpty(string $name, $value = null, array $options = null): string
{
return $this->currencyField($name, 'amount', $value, $options);
/** @var CurrencyRepositoryInterface $currencyRepos */
$currencyRepos = app(CurrencyRepositoryInterface::class);
// get all currencies:
$list = $currencyRepos->get();
$array = [
0 => (string)trans('firefly.no_currency'),
];
/** @var TransactionCurrency $currency */
foreach ($list as $currency) {
$array[$currency->id] = $currency->name . ' (' . $currency->symbol . ')';
}
return $this->select($name, $array, $value, $options);
}
}

View File

@@ -38,30 +38,6 @@ trait FormSupport
{
/**
* @return AccountRepositoryInterface
*/
protected function getAccountRepository(): AccountRepositoryInterface
{
return app(AccountRepositoryInterface::class);
}
/**
* @return Carbon
*/
protected function getDate(): Carbon
{
/** @var Carbon $date */
$date = null;
try {
$date = today(config('app.timezone'));
} catch (Exception $e) {
$e->getMessage();
}
return $date;
}
/**
* @param string $name
* @param array $list
@@ -88,6 +64,23 @@ trait FormSupport
return $html;
}
/**
* @param $name
* @param $options
*
* @return string
*/
protected function label(string $name, array $options = null): string
{
$options = $options ?? [];
if (isset($options['label'])) {
return $options['label'];
}
$name = str_replace('[]', '', $name);
return (string)trans('form.' . $name);
}
/**
* @param $name
* @param $label
@@ -107,6 +100,25 @@ trait FormSupport
return $options;
}
/**
* @param $name
*
* @return string
*/
protected function getHolderClasses(string $name): string
{
// Get errors from session:
/** @var MessageBag $errors */
$errors = session('errors');
$classes = 'form-group';
if (null !== $errors && $errors->has($name)) {
$classes = 'form-group has-error has-feedback';
}
return $classes;
}
/**
* @param string $name
* @param $value
@@ -137,38 +149,26 @@ trait FormSupport
}
/**
* @param $name
*
* @return string
* @return AccountRepositoryInterface
*/
protected function getHolderClasses(string $name): string
protected function getAccountRepository(): AccountRepositoryInterface
{
// Get errors from session:
/** @var MessageBag $errors */
$errors = session('errors');
$classes = 'form-group';
if (null !== $errors && $errors->has($name)) {
$classes = 'form-group has-error has-feedback';
}
return $classes;
return app(AccountRepositoryInterface::class);
}
/**
* @param $name
* @param $options
*
* @return string
* @return Carbon
*/
protected function label(string $name, array $options = null): string
protected function getDate(): Carbon
{
$options = $options ?? [];
if (isset($options['label'])) {
return $options['label'];
/** @var Carbon $date */
$date = null;
try {
$date = today(config('app.timezone'));
} catch (Exception $e) {
$e->getMessage();
}
$name = str_replace('[]', '', $name);
return (string)trans('form.' . $name);
return $date;
}
}

View File

@@ -40,8 +40,8 @@ class PiggyBankForm
* TODO cleanup and describe.
*
* @param string $name
* @param mixed $value
* @param array $options
* @param mixed $value
* @param array $options
*
* @return string
*/
@@ -51,7 +51,7 @@ class PiggyBankForm
/** @var PiggyBankRepositoryInterface $repository */
$repository = app(PiggyBankRepositoryInterface::class);
$piggyBanks = $repository->getPiggyBanksWithAmount();
$title = (string) trans('firefly.default_group_title_name');
$title = (string)trans('firefly.default_group_title_name');
$array = [];
$subList = [
0 => [
@@ -59,7 +59,7 @@ class PiggyBankForm
'title' => $title,
],
'piggies' => [
(string) trans('firefly.none_in_select_list'),
(string)trans('firefly.none_in_select_list'),
],
],
];

View File

@@ -36,10 +36,11 @@ use Illuminate\Support\HtmlString;
class RuleForm
{
use FormSupport;
/**
* @param string $name
* @param mixed $value
* @param array $options
* @param mixed $value
* @param array $options
*
* @return string
*/
@@ -60,8 +61,8 @@ class RuleForm
}
/**
* @param string $name
* @param null $value
* @param string $name
* @param null $value
* @param array|null $options
*
* @return HtmlString

View File

@@ -27,6 +27,7 @@ use FireflyIII\Models\AccountType;
/**
* Trait AccountFilter
*
* @codeCoverageIgnore
*/
trait AccountFilter
@@ -40,7 +41,7 @@ trait AccountFilter
*/
protected function mapAccountTypes(string $type): array
{
$types = [
$types = [
'all' => [AccountType::DEFAULT, AccountType::CASH,
AccountType::ASSET, AccountType::EXPENSE, AccountType::REVENUE,
AccountType::INITIAL_BALANCE, AccountType::BENEFICIARY, AccountType::IMPORT, AccountType::RECONCILIATION,

View File

@@ -28,6 +28,7 @@ use Illuminate\Support\Collection;
/**
* Trait ApiSupport
*
* @codeCoverageIgnore
*/
trait ApiSupport

View File

@@ -27,6 +27,7 @@ use FireflyIII\Models\TransactionType;
/**
* Trait TransactionFilter
*
* @codeCoverageIgnore
*/
trait TransactionFilter
@@ -40,7 +41,7 @@ trait TransactionFilter
*/
protected function mapTransactionTypes(string $type): array
{
$types = [
$types = [
'all' => [TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER, TransactionType::OPENING_BALANCE,
TransactionType::RECONCILIATION,],
'withdrawal' => [TransactionType::WITHDRAWAL,],
@@ -59,6 +60,7 @@ trait TransactionFilter
'specials' => [TransactionType::OPENING_BALANCE, TransactionType::RECONCILIATION,],
'default' => [TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER,],
];
return $types[$type] ?? $types['default'];

View File

@@ -208,7 +208,7 @@ trait AugumentData
$cache->addProperty('get-limits');
if ($cache->has()) {
return $cache->get(); // @codeCoverageIgnore
return $cache->get(); // @codeCoverageIgnore
}
$set = $blRepository->getBudgetLimits($budget, $start, $end);

View File

@@ -30,6 +30,7 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\User;
use Laravel\Passport\Passport;
use Log;
use phpseclib3\Crypt\RSA;
/**
* Trait CreateStuff
@@ -41,7 +42,7 @@ trait CreateStuff
/**
* Creates an asset account.
*
* @param NewUserFormRequest $request
* @param NewUserFormRequest $request
* @param TransactionCurrency $currency
*
* @return bool
@@ -57,7 +58,7 @@ trait CreateStuff
'virtual_balance' => 0,
'account_type_id' => null,
'active' => true,
'account_role' => 'defaultAsset',
'account_role' => 'defaultAsset',
'opening_balance' => $request->input('bank_balance'),
'opening_balance_date' => new Carbon,
'currency_id' => $currency->id,
@@ -72,7 +73,7 @@ trait CreateStuff
* Creates a cash wallet.
*
* @param TransactionCurrency $currency
* @param string $language
* @param string $language
*
* @return bool
*/
@@ -87,7 +88,7 @@ trait CreateStuff
'virtual_balance' => 0,
'account_type_id' => null,
'active' => true,
'account_role' => 'cashWalletAsset',
'account_role' => 'cashWalletAsset',
'opening_balance' => null,
'opening_balance_date' => null,
'currency_id' => $currency->id,
@@ -109,7 +110,7 @@ trait CreateStuff
$keys = $rsa->createKey(4096);
}
if (8 === PHP_MAJOR_VERSION) {
$keys = \phpseclib3\Crypt\RSA::createKeys(4096);
$keys = RSA::createKeys(4096);
}
[$publicKey, $privateKey] = [
@@ -130,9 +131,9 @@ trait CreateStuff
/**
* Create a savings account.
*
* @param NewUserFormRequest $request
* @param NewUserFormRequest $request
* @param TransactionCurrency $currency
* @param string $language
* @param string $language
*
* @return bool
*/
@@ -162,7 +163,7 @@ trait CreateStuff
*
* @param array $data
*
* @return \FireflyIII\User
* @return User
*/
protected function createUser(array $data): User // create object
{

View File

@@ -33,6 +33,25 @@ use FireflyIII\Support\Cronjobs\TelemetryCronjob;
*/
trait CronRunner
{
/**
* @return string
*/
protected function runAutoBudget(): string
{
/** @var AutoBudgetCronjob $autoBudget */
$autoBudget = app(AutoBudgetCronjob::class);
try {
$result = $autoBudget->fire();
} catch (FireflyException $e) {
return $e->getMessage();
}
if (false === $result) {
return 'The auto budget cron job did not fire.';
}
return 'The auto budget cron job fired successfully.';
}
/**
* @return string
*/
@@ -55,7 +74,8 @@ trait CronRunner
/**
* @return string
*/
protected function runTelemetry(): string {
protected function runTelemetry(): string
{
/** @var TelemetryCronjob $telemetry */
$telemetry = app(TelemetryCronjob::class);
try {
@@ -70,23 +90,4 @@ trait CronRunner
return 'The telemetry cron job fired successfully.';
}
/**
* @return string
*/
protected function runAutoBudget(): string
{
/** @var AutoBudgetCronjob $autoBudget */
$autoBudget = app(AutoBudgetCronjob::class);
try {
$result = $autoBudget->fire();
} catch (FireflyException $e) {
return $e->getMessage();
}
if (false === $result) {
return 'The auto budget cron job did not fire.';
}
return 'The auto budget cron job fired successfully.';
}
}

View File

@@ -50,6 +50,7 @@ trait DateCalculation
if ($start->lte($today) && $end->gte($today)) {
$difference = $today->diffInDays($end);
}
return 0 === $difference ? 1 : $difference;
}

View File

@@ -42,7 +42,7 @@ trait GetConfigurationData
*/
protected function errorReporting(int $value): string // get configuration
{
$array = [
$array = [
-1 => 'ALL errors',
E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED => 'E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED',
E_ALL => 'E_ALL',
@@ -51,6 +51,7 @@ trait GetConfigurationData
E_ALL & ~E_NOTICE & ~E_STRICT => 'E_ALL & ~E_NOTICE & ~E_STRICT',
E_COMPILE_ERROR | E_RECOVERABLE_ERROR | E_ERROR | E_CORE_ERROR => 'E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR',
];
return $array[$value] ?? (string)$value;
}
@@ -90,7 +91,7 @@ trait GetConfigurationData
*/
protected function getDateRangeConfig(): array // get configuration + get preferences.
{
$viewRange = (string) app('preferences')->get('viewRange', '1M')->data;
$viewRange = (string)app('preferences')->get('viewRange', '1M')->data;
/** @var Carbon $start */
$start = session('start');
/** @var Carbon $end */
@@ -197,6 +198,7 @@ trait GetConfigurationData
return $steps;
}
/**
*
*/

View File

@@ -86,9 +86,9 @@ trait ModelInformation
$mortgage = $repository->getAccountTypeByType(AccountType::MORTGAGE);
/** @noinspection NullPointerExceptionInspection */
$liabilityTypes = [
$debt->id => (string) trans(sprintf('firefly.account_type_%s', AccountType::DEBT)),
$loan->id => (string) trans(sprintf('firefly.account_type_%s', AccountType::LOAN)),
$mortgage->id => (string) trans(sprintf('firefly.account_type_%s', AccountType::MORTGAGE)),
$debt->id => (string)trans(sprintf('firefly.account_type_%s', AccountType::DEBT)),
$loan->id => (string)trans(sprintf('firefly.account_type_%s', AccountType::LOAN)),
$mortgage->id => (string)trans(sprintf('firefly.account_type_%s', AccountType::MORTGAGE)),
];
asort($liabilityTypes);
@@ -103,7 +103,7 @@ trait ModelInformation
{
$roles = [];
foreach (config('firefly.accountRoles') as $role) {
$roles[$role] = (string) trans(sprintf('firefly.account_role_%s', $role));
$roles[$role] = (string)trans(sprintf('firefly.account_role_%s', $role));
}
return $roles;
@@ -124,7 +124,7 @@ trait ModelInformation
foreach ($operators as $key => $operator) {
if ('user_action' !== $key && false === $operator['alias']) {
$triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key));
$triggers[$key] = (string)trans(sprintf('firefly.rule_trigger_%s_choice', $key));
}
}
asort($triggers);
@@ -133,8 +133,8 @@ trait ModelInformation
$billTriggers = ['currency_is', 'amount_more', 'amount_less', 'description_contains'];
$values = [
$bill->transactionCurrency()->first()->name,
round((float) $bill->amount_min, 12),
round((float) $bill->amount_max, 12),
round((float)$bill->amount_min, 12),
round((float)$bill->amount_max, 12),
$bill->name,
];
foreach ($billTriggers as $index => $trigger) {
@@ -178,7 +178,7 @@ trait ModelInformation
foreach ($operators as $key => $operator) {
if ('user_action' !== $key && false === $operator['alias']) {
$triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key));
$triggers[$key] = (string)trans(sprintf('firefly.rule_trigger_%s_choice', $key));
}
}
asort($triggers);

View File

@@ -70,8 +70,8 @@ trait PeriodOverview
* performance reasons.
*
* @param Account $account The account involved
* @param Carbon $date The start date.
* @param Carbon $end The end date.
* @param Carbon $date The start date.
* @param Carbon $end The end date.
*
* @return array
*/
@@ -124,30 +124,145 @@ trait PeriodOverview
$spent = $this->filterJournalsByDate($spentSet, $currentDate['start'], $currentDate['end']);
$transferredAway = $this->filterTransferredAway($account, $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end']));
$transferredIn = $this->filterTransferredIn($account, $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end']));
$entries[] =
[
'title' => $title,
'route' =>
route('accounts.show', [$account->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
$entries[]
= [
'title' => $title,
'route' =>
route('accounts.show', [$account->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
'total_transactions' => count($spent) + count($earned) + count($transferredAway) + count($transferredIn),
'spent' => $this->groupByCurrency($spent),
'earned' => $this->groupByCurrency($earned),
'transferred_away' => $this->groupByCurrency($transferredAway),
'transferred_in' => $this->groupByCurrency($transferredIn),
];
'total_transactions' => count($spent) + count($earned) + count($transferredAway) + count($transferredIn),
'spent' => $this->groupByCurrency($spent),
'earned' => $this->groupByCurrency($earned),
'transferred_away' => $this->groupByCurrency($transferredAway),
'transferred_in' => $this->groupByCurrency($transferredIn),
];
}
$cache->store($entries);
return $entries;
}
/**
* Filter a list of journals by a set of dates, and then group them by currency.
*
* @param array $array
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
private function filterJournalsByDate(array $array, Carbon $start, Carbon $end): array
{
$result = [];
/** @var array $journal */
foreach ($array as $journal) {
if ($journal['date'] <= $end && $journal['date'] >= $start) {
$result[] = $journal;
}
}
return $result;
}
/**
* Return only transactions where $account is the source.
*
* @param Account $account
* @param array $journals
*
* @return array
*/
private function filterTransferredAway(Account $account, array $journals): array
{
$return = [];
/** @var array $journal */
foreach ($journals as $journal) {
if ($account->id === (int)$journal['source_account_id']) {
$return[] = $journal;
}
}
return $return;
}
/**
* Return only transactions where $account is the source.
*
* @param Account $account
* @param array $journals
*
* @return array
* @codeCoverageIgnore
*/
private function filterTransferredIn(Account $account, array $journals): array
{
$return = [];
/** @var array $journal */
foreach ($journals as $journal) {
if ($account->id === (int)$journal['destination_account_id']) {
$return[] = $journal;
}
}
return $return;
}
/**
* @param array $journals
*
* @return array
* @codeCoverageIgnore
*/
private function groupByCurrency(array $journals): array
{
$return = [];
/** @var array $journal */
foreach ($journals as $journal) {
$currencyId = (int)$journal['currency_id'];
$foreignCurrencyId = $journal['foreign_currency_id'];
if (!isset($return[$currencyId])) {
$return[$currencyId] = [
'amount' => '0',
'count' => 0,
'currency_id' => $currencyId,
'currency_name' => $journal['currency_name'],
'currency_code' => $journal['currency_code'],
'currency_symbol' => $journal['currency_symbol'],
'currency_decimal_places' => $journal['currency_decimal_places'],
];
}
$return[$currencyId]['amount'] = bcadd($return[$currencyId]['amount'], $journal['amount'] ?? '0');
$return[$currencyId]['count']++;
if (null !== $foreignCurrencyId && null !== $journal['foreign_amount']) {
if (!isset($return[$foreignCurrencyId])) {
$return[$foreignCurrencyId] = [
'amount' => '0',
'count' => 0,
'currency_id' => (int)$foreignCurrencyId,
'currency_name' => $journal['foreign_currency_name'],
'currency_code' => $journal['foreign_currency_code'],
'currency_symbol' => $journal['foreign_currency_symbol'],
'currency_decimal_places' => $journal['foreign_currency_decimal_places'],
];
}
$return[$foreignCurrencyId]['count']++;
$return[$foreignCurrencyId]['amount'] = bcadd($return[$foreignCurrencyId]['amount'], $journal['foreign_amount']);
}
}
return $return;
}
/**
* Overview for single category. Has been refactored recently.
*
* @param Category $category
* @param Carbon $start
* @param Carbon $end
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
protected function getCategoryPeriodOverview(Category $category, Carbon $start, Carbon $end): array
@@ -200,17 +315,19 @@ trait PeriodOverview
$earned = $this->filterJournalsByDate($earnedSet, $currentDate['start'], $currentDate['end']);
$transferred = $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end']);
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
$entries[] =
[
'transactions' => 0,
'title' => $title,
'route' => route('categories.show',
[$category->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
'total_transactions' => count($spent) + count($earned) + count($transferred),
'spent' => $this->groupByCurrency($spent),
'earned' => $this->groupByCurrency($earned),
'transferred' => $this->groupByCurrency($transferred),
];
$entries[]
= [
'transactions' => 0,
'title' => $title,
'route' => route(
'categories.show',
[$category->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]
),
'total_transactions' => count($spent) + count($earned) + count($transferred),
'spent' => $this->groupByCurrency($spent),
'earned' => $this->groupByCurrency($earned),
'transferred' => $this->groupByCurrency($transferred),
];
}
$cache->store($entries);
@@ -254,18 +371,18 @@ trait PeriodOverview
$journals = $collector->getExtractedJournals();
foreach ($dates as $currentDate) {
$set = $this->filterJournalsByDate($journals, $currentDate['start'], $currentDate['end']);
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
$entries[] =
[
'title' => $title,
'route' => route('budgets.no-budget', [$currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
'total_transactions' => count($set),
'spent' => $this->groupByCurrency($set),
'earned' => [],
'transferred_away' => [],
'transferred_in' => [],
];
$set = $this->filterJournalsByDate($journals, $currentDate['start'], $currentDate['end']);
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
$entries[]
= [
'title' => $title,
'route' => route('budgets.no-budget', [$currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
'total_transactions' => count($set),
'spent' => $this->groupByCurrency($set),
'earned' => [],
'transferred_away' => [],
'transferred_in' => [],
];
}
$cache->store($entries);
@@ -336,15 +453,15 @@ trait PeriodOverview
$earned = $this->filterJournalsByDate($earnedSet, $currentDate['start'], $currentDate['end']);
$transferred = $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end']);
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
$entries[] =
[
'title' => $title,
'route' => route('categories.no-category', [$currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
'total_transactions' => count($spent) + count($earned) + count($transferred),
'spent' => $this->groupByCurrency($spent),
'earned' => $this->groupByCurrency($earned),
'transferred' => $this->groupByCurrency($transferred),
];
$entries[]
= [
'title' => $title,
'route' => route('categories.no-category', [$currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
'total_transactions' => count($spent) + count($earned) + count($transferred),
'spent' => $this->groupByCurrency($spent),
'earned' => $this->groupByCurrency($earned),
'transferred' => $this->groupByCurrency($transferred),
];
}
Log::debug('End of loops');
$cache->store($entries);
@@ -355,7 +472,7 @@ trait PeriodOverview
/**
* This shows a period overview for a tag. It goes back in time and lists all relevant transactions and sums.
*
* @param Tag $tag
* @param Tag $tag
*
* @param Carbon $date
*
@@ -374,7 +491,7 @@ trait PeriodOverview
$cache->addProperty('tag-period-entries');
$cache->addProperty($tag->id);
if ($cache->has()) {
return $cache->get(); // @codeCoverageIgnore
return $cache->get(); // @codeCoverageIgnore
}
/** @var array $dates */
$dates = app('navigation')->blockPeriods($start, $end, $range);
@@ -409,17 +526,19 @@ trait PeriodOverview
$earned = $this->filterJournalsByDate($earnedSet, $currentDate['start'], $currentDate['end']);
$transferred = $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end']);
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
$entries[] =
[
'transactions' => 0,
'title' => $title,
'route' => route('tags.show',
[$tag->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
'total_transactions' => count($spent) + count($earned) + count($transferred),
'spent' => $this->groupByCurrency($spent),
'earned' => $this->groupByCurrency($earned),
'transferred' => $this->groupByCurrency($transferred),
];
$entries[]
= [
'transactions' => 0,
'title' => $title,
'route' => route(
'tags.show',
[$tag->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]
),
'total_transactions' => count($spent) + count($earned) + count($transferred),
'spent' => $this->groupByCurrency($spent),
'earned' => $this->groupByCurrency($earned),
'transferred' => $this->groupByCurrency($transferred),
];
}
return $entries;
@@ -473,127 +592,18 @@ trait PeriodOverview
}
$entries[] =
[
'title' => $title,
'route' =>
route('transactions.index', [$transactionType, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
'total_transactions' => count($spent) + count($earned) + count($transferred),
'spent' => $this->groupByCurrency($spent),
'earned' => $this->groupByCurrency($earned),
'transferred' => $this->groupByCurrency($transferred),
];
$entries[]
= [
'title' => $title,
'route' =>
route('transactions.index', [$transactionType, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
'total_transactions' => count($spent) + count($earned) + count($transferred),
'spent' => $this->groupByCurrency($spent),
'earned' => $this->groupByCurrency($earned),
'transferred' => $this->groupByCurrency($transferred),
];
}
return $entries;
}
/**
* Return only transactions where $account is the source.
* @param Account $account
* @param array $journals
* @return array
*/
private function filterTransferredAway(Account $account, array $journals): array
{
$return = [];
/** @var array $journal */
foreach ($journals as $journal) {
if ($account->id === (int)$journal['source_account_id']) {
$return[] = $journal;
}
}
return $return;
}
/**
* Return only transactions where $account is the source.
* @param Account $account
* @param array $journals
* @return array
* @codeCoverageIgnore
*/
private function filterTransferredIn(Account $account, array $journals): array
{
$return = [];
/** @var array $journal */
foreach ($journals as $journal) {
if ($account->id === (int)$journal['destination_account_id']) {
$return[] = $journal;
}
}
return $return;
}
/**
* Filter a list of journals by a set of dates, and then group them by currency.
*
* @param array $array
* @param Carbon $start
* @param Carbon $end
* @return array
*/
private function filterJournalsByDate(array $array, Carbon $start, Carbon $end): array
{
$result = [];
/** @var array $journal */
foreach ($array as $journal) {
if ($journal['date'] <= $end && $journal['date'] >= $start) {
$result[] = $journal;
}
}
return $result;
}
/**
* @param array $journals
*
* @return array
* @codeCoverageIgnore
*/
private function groupByCurrency(array $journals): array
{
$return = [];
/** @var array $journal */
foreach ($journals as $journal) {
$currencyId = (int)$journal['currency_id'];
$foreignCurrencyId = $journal['foreign_currency_id'];
if (!isset($return[$currencyId])) {
$return[$currencyId] = [
'amount' => '0',
'count' => 0,
'currency_id' => $currencyId,
'currency_name' => $journal['currency_name'],
'currency_code' => $journal['currency_code'],
'currency_symbol' => $journal['currency_symbol'],
'currency_decimal_places' => $journal['currency_decimal_places'],
];
}
$return[$currencyId]['amount'] = bcadd($return[$currencyId]['amount'], $journal['amount'] ?? '0');
$return[$currencyId]['count']++;
if (null !== $foreignCurrencyId && null !== $journal['foreign_amount']) {
if (!isset($return[$foreignCurrencyId])) {
$return[$foreignCurrencyId] = [
'amount' => '0',
'count' => 0,
'currency_id' => (int)$foreignCurrencyId,
'currency_name' => $journal['foreign_currency_name'],
'currency_code' => $journal['foreign_currency_code'],
'currency_symbol' => $journal['foreign_currency_symbol'],
'currency_decimal_places' => $journal['foreign_currency_decimal_places'],
];
}
$return[$foreignCurrencyId]['count']++;
$return[$foreignCurrencyId]['amount'] = bcadd($return[$foreignCurrencyId]['amount'], $journal['foreign_amount']);
}
}
return $return;
}
}

View File

@@ -45,50 +45,6 @@ use Throwable;
trait RenderPartialViews
{
/**
* Get options for double report.
*
* @return string
*/
protected function doubleReportOptions(): string // render a view
{
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$expense = $repository->getActiveAccountsByType([AccountType::EXPENSE, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]);
$revenue = $repository->getActiveAccountsByType([AccountType::REVENUE, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]);
$set = [];
/** @var Account $account */
foreach ($expense as $account) {
// loop revenue, find same account:
/** @var Account $otherAccount */
foreach ($revenue as $otherAccount) {
if (
(
($otherAccount->name === $account->name)
||
(null !== $account->iban && null !== $otherAccount->iban && $otherAccount->iban === $account->iban)
)
&& $otherAccount->id !== $account->id
) {
$set[] = $account;
}
}
}
// @codeCoverageIgnoreStart
try {
$result = prefixView('reports.options.double', compact('set'))->render();
} catch (Throwable $e) {
Log::error(sprintf('Cannot render reports.options.tag: %s', $e->getMessage()));
$result = 'Could not render view.';
}
// @codeCoverageIgnoreEnd
return $result;
}
/**
* View for transactions in a budget for an account.
*
@@ -103,10 +59,10 @@ trait RenderPartialViews
/** @var BudgetRepositoryInterface $budgetRepository */
$budgetRepository = app(BudgetRepositoryInterface::class);
$budget = $budgetRepository->findNull((int) $attributes['budgetId']);
$budget = $budgetRepository->findNull((int)$attributes['budgetId']);
$accountRepos = app(AccountRepositoryInterface::class);
$account = $accountRepos->findNull((int) $attributes['accountId']);
$account = $accountRepos->findNull((int)$attributes['accountId']);
$journals = $popupHelper->balanceForBudget($budget, $account, $attributes);
// @codeCoverageIgnoreStart
@@ -160,7 +116,7 @@ trait RenderPartialViews
/** @var PopupReportInterface $popupHelper */
$popupHelper = app(PopupReportInterface::class);
$budget = $budgetRepository->findNull((int) $attributes['budgetId']);
$budget = $budgetRepository->findNull((int)$attributes['budgetId']);
if (null === $budget) {
$budget = new Budget;
}
@@ -192,7 +148,7 @@ trait RenderPartialViews
/** @var CategoryRepositoryInterface $categoryRepository */
$categoryRepository = app(CategoryRepositoryInterface::class);
$category = $categoryRepository->findNull((int) $attributes['categoryId']);
$category = $categoryRepository->findNull((int)$attributes['categoryId']);
$journals = $popupHelper->byCategory($category, $attributes);
try {
@@ -228,6 +184,49 @@ trait RenderPartialViews
return $result;
}
/**
* Get options for double report.
*
* @return string
*/
protected function doubleReportOptions(): string // render a view
{
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$expense = $repository->getActiveAccountsByType([AccountType::EXPENSE, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]);
$revenue = $repository->getActiveAccountsByType([AccountType::REVENUE, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]);
$set = [];
/** @var Account $account */
foreach ($expense as $account) {
// loop revenue, find same account:
/** @var Account $otherAccount */
foreach ($revenue as $otherAccount) {
if (
(
($otherAccount->name === $account->name)
|| (null !== $account->iban && null !== $otherAccount->iban && $otherAccount->iban === $account->iban)
)
&& $otherAccount->id !== $account->id
) {
$set[] = $account;
}
}
}
// @codeCoverageIgnoreStart
try {
$result = prefixView('reports.options.double', compact('set'))->render();
} catch (Throwable $e) {
Log::error(sprintf('Cannot render reports.options.tag: %s', $e->getMessage()));
$result = 'Could not render view.';
}
// @codeCoverageIgnoreEnd
return $result;
}
/**
* Returns all the expenses that went to the given expense account.
*
@@ -243,7 +242,7 @@ trait RenderPartialViews
/** @var PopupReportInterface $popupHelper */
$popupHelper = app(PopupReportInterface::class);
$account = $accountRepository->findNull((int) $attributes['accountId']);
$account = $accountRepository->findNull((int)$attributes['accountId']);
if (null === $account) {
return 'This is an unknown account. Apologies.';
@@ -317,7 +316,7 @@ trait RenderPartialViews
foreach ($operators as $key => $operator) {
if ('user_action' !== $key && false === $operator['alias']) {
$triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key));
$triggers[$key] = (string)trans(sprintf('firefly.rule_trigger_%s_choice', $key));
}
}
asort($triggers);
@@ -369,7 +368,7 @@ trait RenderPartialViews
/** @var PopupReportInterface $popupHelper */
$popupHelper = app(PopupReportInterface::class);
$account = $accountRepository->findNull((int) $attributes['accountId']);
$account = $accountRepository->findNull((int)$attributes['accountId']);
if (null === $account) {
return 'This is an unknown category. Apologies.';

View File

@@ -98,6 +98,7 @@ trait RequestInformation
// also check cache first:
if ($help->inCache($route, $language)) {
Log::debug(sprintf('Help text %s was in cache.', $language));
return $help->getFromCache($route, $language);
}
$baseHref = route('index');
@@ -117,6 +118,24 @@ trait RequestInformation
return '<p>' . trans('firefly.route_has_no_help') . '</p>'; // @codeCoverageIgnore
}
/**
* @return string
*/
protected function getPageName(): string // get request info
{
return str_replace('.', '_', RouteFacade::currentRouteName());
}
/**
* Get the specific name of a page for intro.
*
* @return string
*/
protected function getSpecificPageName(): string // get request info
{
return null === RouteFacade::current()->parameter('objectType') ? '' : '_' . RouteFacade::current()->parameter('objectType');
}
/**
* Get a list of triggers.
*
@@ -152,7 +171,6 @@ trait RequestInformation
$specificPage = $this->getSpecificPageName();
// indicator if user has seen the help for this page ( + special page):
$key = sprintf('shown_demo_%s%s', $page, $specificPage);
// is there an intro for this route?
@@ -172,24 +190,6 @@ trait RequestInformation
return $shownDemo;
}
/**
* @return string
*/
protected function getPageName(): string // get request info
{
return str_replace('.', '_', RouteFacade::currentRouteName());
}
/**
* Get the specific name of a page for intro.
*
* @return string
*/
protected function getSpecificPageName(): string // get request info
{
return null === RouteFacade::current()->parameter('objectType') ? '' : '_' . RouteFacade::current()->parameter('objectType');
}
/**
* Check if date is outside session range.
*
@@ -249,7 +249,7 @@ trait RequestInformation
/**
* Validate users new password.
*
* @param User $user
* @param User $user
* @param string $current
* @param string $new
*

View File

@@ -36,8 +36,138 @@ use Throwable;
*/
trait RuleManagement
{
/**
*
*/
protected function createDefaultRule(): void
{
/** @var RuleRepositoryInterface $ruleRepository */
$ruleRepository = app(RuleRepositoryInterface::class);
if (0 === $ruleRepository->count()) {
$data = [
'rule_group_id' => $ruleRepository->getFirstRuleGroup()->id,
'stop_processing' => 0,
'title' => (string)trans('firefly.default_rule_name'),
'description' => (string)trans('firefly.default_rule_description'),
'trigger' => 'store-journal',
'strict' => true,
'active' => true,
'triggers' => [
[
'type' => 'description_is',
'value' => (string)trans('firefly.default_rule_trigger_description'),
'stop_processing' => false,
],
[
'type' => 'from_account_is',
'value' => (string)trans('firefly.default_rule_trigger_from_account'),
'stop_processing' => false,
],
],
'actions' => [
[
'type' => 'prepend_description',
'value' => (string)trans('firefly.default_rule_action_prepend'),
'stop_processing' => false,
],
[
'type' => 'set_category',
'value' => (string)trans('firefly.default_rule_action_set_category'),
'stop_processing' => false,
],
],
];
$ruleRepository->store($data);
}
}
/**
* @param Request $request
*
* @return array
* @codeCoverageIgnore
*/
protected function getPreviousActions(Request $request): array
{
$index = 0;
$triggers = [];
$oldInput = $request->old('actions');
if (is_array($oldInput)) {
foreach ($oldInput as $oldAction) {
try {
$triggers[] = prefixView(
'rules.partials.action',
[
'oldAction' => $oldAction['type'],
'oldValue' => $oldAction['value'],
'oldChecked' => 1 === (int)($oldAction['stop_processing'] ?? '0'),
'count' => $index + 1,
]
)->render();
} catch (Throwable $e) {
Log::debug(sprintf('Throwable was thrown in getPreviousActions(): %s', $e->getMessage()));
Log::error($e->getTraceAsString());
}
$index++;
}
}
return $triggers;
}
/**
* @param Request $request
*
* @return array
* @codeCoverageIgnore
*/
protected function getPreviousTriggers(Request $request): array
{
// TODO duplicated code.
$operators = config('firefly.search.operators');
$triggers = [];
foreach ($operators as $key => $operator) {
if ('user_action' !== $key && false === $operator['alias']) {
$triggers[$key] = (string)trans(sprintf('firefly.rule_trigger_%s_choice', $key));
}
}
asort($triggers);
$index = 0;
$renderedEntries = [];
$oldInput = $request->old('triggers');
if (is_array($oldInput)) {
foreach ($oldInput as $oldTrigger) {
try {
$renderedEntries[] = prefixView(
'rules.partials.trigger',
[
'oldTrigger' => OperatorQuerySearch::getRootOperator($oldTrigger['type']),
'oldValue' => $oldTrigger['value'],
'oldChecked' => 1 === (int)($oldTrigger['stop_processing'] ?? '0'),
'count' => $index + 1,
'triggers' => $triggers,
]
)->render();
} catch (Throwable $e) {
Log::debug(sprintf('Throwable was thrown in getPreviousTriggers(): %s', $e->getMessage()));
Log::error($e->getTraceAsString());
}
$index++;
}
}
return $renderedEntries;
}
/**
* @param array $submittedOperators
*
* @return array
*/
protected function parseFromOperators(array $submittedOperators): array
@@ -49,7 +179,7 @@ trait RuleManagement
foreach ($operators as $key => $operator) {
if ('user_action' !== $key && false === $operator['alias']) {
$triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key));
$triggers[$key] = (string)trans(sprintf('firefly.rule_trigger_%s_choice', $key));
}
}
asort($triggers);
@@ -77,135 +207,6 @@ trait RuleManagement
return $renderedEntries;
}
/**
*
*/
protected function createDefaultRule(): void
{
/** @var RuleRepositoryInterface $ruleRepository */
$ruleRepository = app(RuleRepositoryInterface::class);
if (0 === $ruleRepository->count()) {
$data = [
'rule_group_id' => $ruleRepository->getFirstRuleGroup()->id,
'stop_processing' => 0,
'title' => (string) trans('firefly.default_rule_name'),
'description' => (string) trans('firefly.default_rule_description'),
'trigger' => 'store-journal',
'strict' => true,
'active' => true,
'triggers' => [
[
'type' => 'description_is',
'value' => (string) trans('firefly.default_rule_trigger_description'),
'stop_processing' => false,
],
[
'type' => 'from_account_is',
'value' => (string) trans('firefly.default_rule_trigger_from_account'),
'stop_processing' => false,
],
],
'actions' => [
[
'type' => 'prepend_description',
'value' => (string) trans('firefly.default_rule_action_prepend'),
'stop_processing' => false,
],
[
'type' => 'set_category',
'value' => (string) trans('firefly.default_rule_action_set_category'),
'stop_processing' => false,
],
],
];
$ruleRepository->store($data);
}
}
/**
* @param Request $request
*
* @return array
* @codeCoverageIgnore
*/
protected function getPreviousActions(Request $request): array
{
$index = 0;
$triggers = [];
$oldInput = $request->old('actions');
if (is_array($oldInput)) {
foreach ($oldInput as $oldAction) {
try {
$triggers[] = prefixView(
'rules.partials.action',
[
'oldAction' => $oldAction['type'],
'oldValue' => $oldAction['value'],
'oldChecked' => 1 === (int) ($oldAction['stop_processing'] ?? '0'),
'count' => $index + 1,
]
)->render();
} catch (Throwable $e) {
Log::debug(sprintf('Throwable was thrown in getPreviousActions(): %s', $e->getMessage()));
Log::error($e->getTraceAsString());
}
$index++;
}
}
return $triggers;
}
/**
* @param Request $request
*
* @return array
* @codeCoverageIgnore
*/
protected function getPreviousTriggers(Request $request): array
{
// TODO duplicated code.
$operators = config('firefly.search.operators');
$triggers = [];
foreach ($operators as $key => $operator) {
if ('user_action' !== $key && false === $operator['alias']) {
$triggers[$key] = (string) trans(sprintf('firefly.rule_trigger_%s_choice', $key));
}
}
asort($triggers);
$index = 0;
$renderedEntries = [];
$oldInput = $request->old('triggers');
if (is_array($oldInput)) {
foreach ($oldInput as $oldTrigger) {
try {
$renderedEntries[] = prefixView(
'rules.partials.trigger',
[
'oldTrigger' => OperatorQuerySearch::getRootOperator($oldTrigger['type']),
'oldValue' => $oldTrigger['value'],
'oldChecked' => 1 === (int) ($oldTrigger['stop_processing'] ?? '0'),
'count' => $index + 1,
'triggers' => $triggers,
]
)->render();
} catch (Throwable $e) {
Log::debug(sprintf('Throwable was thrown in getPreviousTriggers(): %s', $e->getMessage()));
Log::error($e->getTraceAsString());
}
$index++;
}
}
return $renderedEntries;
}
/**
*
*/
@@ -215,8 +216,8 @@ trait RuleManagement
$repository = app(RuleGroupRepositoryInterface::class);
if (0 === $repository->count()) {
$data = [
'title' => (string) trans('firefly.default_rule_group_name'),
'description' => (string) trans('firefly.default_rule_group_description'),
'title' => (string)trans('firefly.default_rule_group_name'),
'description' => (string)trans('firefly.default_rule_group_description'),
'active' => true,
];

View File

@@ -39,8 +39,8 @@ trait TransactionCalculation
*
* @param Collection $accounts
* @param Collection $opposing
* @param Carbon $start
* @param Carbon $end
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
@@ -63,8 +63,8 @@ trait TransactionCalculation
*
* @param Collection $accounts
* @param Collection $tags
* @param Carbon $start
* @param Carbon $end
* @param Carbon $start
* @param Carbon $end
*
* @return array
*
@@ -85,8 +85,8 @@ trait TransactionCalculation
*
* @param Collection $accounts
* @param Collection $budgets
* @param Carbon $start
* @param Carbon $end
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
@@ -105,8 +105,8 @@ trait TransactionCalculation
*
* @param Collection $accounts
* @param Collection $categories
* @param Carbon $start
* @param Carbon $end
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
@@ -129,8 +129,8 @@ trait TransactionCalculation
*
* @param Collection $accounts
* @param Collection $categories
* @param Carbon $start
* @param Carbon $end
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
@@ -149,14 +149,14 @@ trait TransactionCalculation
*
* @param Collection $accounts
* @param Collection $opposing
* @param Carbon $start
* @param Carbon $end
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
protected function getIncomeForOpposing(Collection $accounts, Collection $opposing, Carbon $start, Carbon $end): array
{
$total =$accounts->merge($opposing);
$total = $accounts->merge($opposing);
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts($total)->setRange($start, $end)->withAccountInformation()->setTypes([TransactionType::DEPOSIT]);
@@ -169,8 +169,8 @@ trait TransactionCalculation
*
* @param Collection $accounts
* @param Collection $tags
* @param Carbon $start
* @param Carbon $end
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/

View File

@@ -29,6 +29,8 @@ use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use Illuminate\Http\RedirectResponse;
use Illuminate\Routing\Redirector;
use Illuminate\Support\Str;
use Illuminate\Support\ViewErrorBag;
use Log;
@@ -40,6 +42,33 @@ use Log;
trait UserNavigation
{
/**
* Functionality:.
*
* - If the $identifier contains the word "delete" then a remembered uri with the text "/show/" in it will not be returned but instead the index (/)
* will be returned.
* - If the remembered uri contains "jscript/" the remembered uri will not be returned but instead the index (/) will be returned.
*
* @param string $identifier
*
* @return string
*/
protected function getPreviousUri(string $identifier): string
{
Log::debug(sprintf('Trying to retrieve URL stored under "%s"', $identifier));
$uri = (string)session($identifier);
Log::debug(sprintf('The URI is %s', $uri));
if (false !== strpos($uri, 'jscript')) {
$uri = $this->redirectUri; // @codeCoverageIgnore
Log::debug(sprintf('URI is now %s (uri contains jscript)', $uri));
}
Log::debug(sprintf('Return direct link %s', $uri));
return $uri;
}
/**
* Will return false if you cant edit this account type.
*
@@ -73,38 +102,10 @@ trait UserNavigation
return in_array($type, $editable, true);
}
/**
* @param TransactionGroup $group
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
protected function redirectGroupToAccount(TransactionGroup $group)
{
/** @var TransactionJournal $journal */
$journal = $group->transactionJournals()->first();
if (null === $journal) {
Log::error(sprintf('No journals in group #%d', $group->id));
return redirect(route('index'));
}
// prefer redirect to everything but expense and revenue:
$transactions = $journal->transactions;
$ignore = [AccountType::REVENUE, AccountType::EXPENSE, AccountType::RECONCILIATION, AccountType::INITIAL_BALANCE];
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
$type = $transaction->account->accountType->type;
if (!in_array($type, $ignore, true)) {
return redirect(route('accounts.edit', [$transaction->account_id]));
}
}
return redirect(route('index'));
}
/**
* @param Account $account
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @return RedirectResponse|Redirector
*/
protected function redirectAccountToAccount(Account $account)
{
@@ -136,31 +137,32 @@ trait UserNavigation
return redirect(route('index'));
}
/**
* Functionality:.
* @param TransactionGroup $group
*
* - If the $identifier contains the word "delete" then a remembered uri with the text "/show/" in it will not be returned but instead the index (/)
* will be returned.
* - If the remembered uri contains "jscript/" the remembered uri will not be returned but instead the index (/) will be returned.
*
* @param string $identifier
*
* @return string
* @return RedirectResponse|Redirector
*/
protected function getPreviousUri(string $identifier): string
protected function redirectGroupToAccount(TransactionGroup $group)
{
Log::debug(sprintf('Trying to retrieve URL stored under "%s"', $identifier));
$uri = (string)session($identifier);
Log::debug(sprintf('The URI is %s', $uri));
/** @var TransactionJournal $journal */
$journal = $group->transactionJournals()->first();
if (null === $journal) {
Log::error(sprintf('No journals in group #%d', $group->id));
if (false !== strpos($uri, 'jscript')) {
$uri = $this->redirectUri; // @codeCoverageIgnore
Log::debug(sprintf('URI is now %s (uri contains jscript)', $uri));
return redirect(route('index'));
}
// prefer redirect to everything but expense and revenue:
$transactions = $journal->transactions;
$ignore = [AccountType::REVENUE, AccountType::EXPENSE, AccountType::RECONCILIATION, AccountType::INITIAL_BALANCE];
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
$type = $transaction->account->accountType->type;
if (!in_array($type, $ignore, true)) {
return redirect(route('accounts.edit', [$transaction->account_id]));
}
}
Log::debug(sprintf('Return direct link %s', $uri));
return $uri;
return redirect(route('index'));
}
/**
@@ -178,6 +180,7 @@ trait UserNavigation
Log::debug(sprintf('Saving URL %s under key %s', $return, $identifier));
session()->put($identifier, $return);
}
return $return;
}
}

View File

@@ -30,6 +30,7 @@ use Monolog\Handler\AbstractProcessingHandler;
/**
* Class AuditLogger
*
* @codeCoverageIgnore
*/
class AuditLogger
@@ -37,7 +38,7 @@ class AuditLogger
/**
* Customize the given logger instance.
*
* @param Logger $logger
* @param Logger $logger
*
* @return void
*/

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Support\Logging;
/**
* Class AuditProcessor
*
* @codeCoverageIgnore
*/
class AuditProcessor
@@ -39,21 +40,24 @@ class AuditProcessor
{
if (auth()->check()) {
$record['message'] = sprintf('AUDIT: %s (%s (%s) -> %s:%s)',
$record['message'],
app('request')->ip(),
auth()->user()->email,
request()->method(), request()->url()
$record['message'] = sprintf(
'AUDIT: %s (%s (%s) -> %s:%s)',
$record['message'],
app('request')->ip(),
auth()->user()->email,
request()->method(), request()->url()
);
return $record;
}
$record['message'] = sprintf('AUDIT: %s (%s -> %s:%s)',
$record['message'],
app('request')->ip(),
request()->method(), request()->url()
$record['message'] = sprintf(
'AUDIT: %s (%s -> %s:%s)',
$record['message'],
app('request')->ip(),
request()->method(), request()->url()
);
return $record;
}
}

View File

@@ -310,10 +310,10 @@ class BudgetReportGenerator
$budgetedPct = '0';
if (0 !== bccomp($spent, '0') && 0 !== bccomp($totalSpent, '0')) {
$spentPct = round((float) bcmul(bcdiv($spent, $totalSpent), '100'));
$spentPct = round((float)bcmul(bcdiv($spent, $totalSpent), '100'));
}
if (0 !== bccomp($budgeted, '0') && 0 !== bccomp($totalBudgeted, '0')) {
$budgetedPct = round((float) bcmul(bcdiv($budgeted, $totalBudgeted), '100'));
$budgetedPct = round((float)bcmul(bcdiv($budgeted, $totalBudgeted), '100'));
}
$this->report['sums'][$currencyId]['budgeted'] = $this->report['sums'][$currencyId]['budgeted'] ?? '0';
$this->report['budgets'][$budgetId]['budget_limits'][$limitId]['spent_pct'] = $spentPct;

View File

@@ -151,7 +151,7 @@ class CategoryReportGenerator
*/
private function processCategoryRow(int $currencyId, array $currencyRow, int $categoryId, array $categoryRow): void
{
$key = sprintf('%s-%s', $currencyId, $categoryId);
$key = sprintf('%s-%s', $currencyId, $categoryId);
$this->report['categories'][$key] = $this->report['categories'][$key] ?? [
'id' => $categoryId,
'title' => $categoryRow['name'],

View File

@@ -80,7 +80,7 @@ trait CalculateRangeOccurrences
}
while ($start < $end) {
$domCorrected = min($dayOfMonth, $start->daysInMonth);
$start->day = $domCorrected;
$start->day = $domCorrected;
if (0 === $attempts % $skipMod && $start->lte($start) && $end->gte($start)) {
$return[] = clone $start;
}
@@ -92,7 +92,6 @@ trait CalculateRangeOccurrences
}
/**
* Get the number of daily occurrences for a recurring transaction until date $end is reached. Will skip every $skipMod-1 occurrences.
*

View File

@@ -62,7 +62,6 @@ trait CalculateXOccurrences
}
/**
* Calculates the number of monthly occurrences for a recurring transaction, starting at the date, until $count is reached. It will skip
* over $skipMod -1 recurrences.
@@ -140,7 +139,6 @@ trait CalculateXOccurrences
}
/**
* Calculates the number of weekly occurrences for a recurring transaction, starting at the date, until $count is reached. It will skip
* over $skipMod -1 recurrences.
@@ -184,7 +182,6 @@ trait CalculateXOccurrences
}
/**
* Calculates the number of yearly occurrences for a recurring transaction, starting at the date, until $count is reached. It will skip
* over $skipMod -1 recurrences.

View File

@@ -30,41 +30,6 @@ use Log;
*/
trait AppendsLocationData
{
/**
* Abstract method stolen from "InteractsWithInput".
*
* @param null $key
* @param bool $default
*
* @return mixed
*/
abstract public function boolean($key = null, $default = false);
/**
* Abstract method.
*
* @param $key
*
* @return bool
*/
abstract public function has($key);
/**
* Abstract method.
*
* @return string
*/
abstract public function method();
/**
* Abstract method.
*
* @param mixed ...$patterns
*
* @return mixed
*/
abstract public function routeIs(...$patterns);
/**
* Read the submitted Request data and add new or updated Location data to the array.
*
@@ -125,15 +90,6 @@ trait AppendsLocationData
return $data;
}
/**
* Abstract method to ensure filling later.
*
* @param string $field
*
* @return string|null
*/
abstract protected function nullableString(string $field): ?string;
/**
* @param string|null $prefix
* @param string $key
@@ -192,6 +148,41 @@ trait AppendsLocationData
return false;
}
/**
* Abstract method stolen from "InteractsWithInput".
*
* @param null $key
* @param bool $default
*
* @return mixed
*/
abstract public function boolean($key = null, $default = false);
/**
* Abstract method.
*
* @param $key
*
* @return bool
*/
abstract public function has($key);
/**
* Abstract method.
*
* @return string
*/
abstract public function method();
/**
* Abstract method.
*
* @param mixed ...$patterns
*
* @return mixed
*/
abstract public function routeIs(...$patterns);
/**
* @param string|null $prefix
*
@@ -199,18 +190,19 @@ trait AppendsLocationData
*/
private function isValidPUT(?string $prefix): bool
{
$longitudeKey = $this->getLocationKey($prefix, 'longitude');
$latitudeKey = $this->getLocationKey($prefix, 'latitude');
$zoomLevelKey = $this->getLocationKey($prefix, 'zoom_level');
$longitudeKey = $this->getLocationKey($prefix, 'longitude');
$latitudeKey = $this->getLocationKey($prefix, 'latitude');
$zoomLevelKey = $this->getLocationKey($prefix, 'zoom_level');
$hasLocationKey = $this->getLocationKey($prefix, 'has_location');
Log::debug('Now in isValidPUT()');
// all fields must be set:
if( null !== $this->get($longitudeKey) && null !== $this->get($latitudeKey) && null !== $this->get($zoomLevelKey)) {
if (null !== $this->get($longitudeKey) && null !== $this->get($latitudeKey) && null !== $this->get($zoomLevelKey)) {
Log::debug('All fields present.');
// must be PUT and API route:
if ('PUT' === $this->method() && $this->routeIs('api.v1.*')) {
Log::debug('Is API location');
return true;
}
// if POST and not API route, must also have "has_location"
@@ -257,4 +249,13 @@ trait AppendsLocationData
}
/**
* Abstract method to ensure filling later.
*
* @param string $field
*
* @return string|null
*/
abstract protected function nullableString(string $field): ?string;
}

View File

@@ -33,46 +33,6 @@ use Log;
trait ConvertsDataTypes
{
/**
* Returns all data in the request, or omits the field if not set,
* according to the config from the request. This is the way.
*
* @param array $fields
*
* @return array
*/
protected function getAllData(array $fields): array
{
$return = [];
foreach ($fields as $field => $info) {
if ($this->has($info[0])) {
$method = $info[1];
$return[$field] = $this->$method($info[0]);
}
}
return $return;
}
/**
* Return date or NULL.
*
* @param string $field
*
* @return Carbon|null
*/
protected function date(string $field): ?Carbon
{
$result = null;
try {
$result = $this->get($field) ? new Carbon($this->get($field)) : null;
} catch (Exception $e) {
Log::debug(sprintf('Exception when parsing date. Not interesting: %s', $e->getMessage()));
}
return $result;
}
/**
* Return integer value.
*
@@ -85,41 +45,28 @@ trait ConvertsDataTypes
return (int)$this->get($field);
}
/**
* Return floating value.
* Return string value, but keep newlines.
*
* @param string $field
*
* @return float|null
* @return string
*/
protected function float(string $field): ?float
public function nlString(string $field): string
{
$res = $this->get($field);
if (null === $res) {
return null;
}
return (float)$res;
return app('steam')->nlCleanString((string)($this->get($field) ?? ''));
}
/**
* Parse and clean a string, but keep the newlines.
* Return string value.
*
* @param string|null $string
* @param string $field
*
* @return string|null
* @return string
*/
protected function nlStringFromValue(?string $string): ?string
public function string(string $field): string
{
if (null === $string) {
return null;
}
$result = app('steam')->nlCleanString($string);
return '' === $result ? null : $result;
return app('steam')->cleanString((string)($this->get($field) ?? ''));
}
/**
@@ -142,6 +89,56 @@ trait ConvertsDataTypes
return null;
}
/**
* @param string $value
*
* @return bool
*/
protected function convertBoolean(?string $value): bool
{
if (null === $value) {
return false;
}
if ('' === $value) {
return false;
}
if ('true' === $value) {
return true;
}
if ('yes' === $value) {
return true;
}
if (1 === $value) {
return true;
}
if ('1' === $value) {
return true;
}
if (true === $value) {
return true;
}
return false;
}
/**
* Return date or NULL.
*
* @param string $field
*
* @return Carbon|null
*/
protected function date(string $field): ?Carbon
{
$result = null;
try {
$result = $this->get($field) ? new Carbon($this->get($field)) : null;
} catch (Exception $e) {
Log::debug(sprintf('Exception when parsing date. Not interesting: %s', $e->getMessage()));
}
return $result;
}
/**
* @param string|null $string
@@ -169,22 +166,42 @@ trait ConvertsDataTypes
}
/**
* Parse and clean a string.
* Return floating value.
*
* @param string|null $string
* @param string $field
*
* @return string|null
* @return float|null
*/
protected function stringFromValue(?string $string): ?string
protected function float(string $field): ?float
{
if (null === $string) {
$res = $this->get($field);
if (null === $res) {
return null;
}
$result = app('steam')->cleanString($string);
return '' === $result ? null : $result;
return (float)$res;
}
/**
* Returns all data in the request, or omits the field if not set,
* according to the config from the request. This is the way.
*
* @param array $fields
*
* @return array
*/
protected function getAllData(array $fields): array
{
$return = [];
foreach ($fields as $field => $info) {
if ($this->has($info[0])) {
$method = $info[1];
$return[$field] = $this->$method($info[0]);
}
}
return $return;
}
/**
* Parse to integer
@@ -206,15 +223,21 @@ trait ConvertsDataTypes
}
/**
* Return string value, but keep newlines.
* Parse and clean a string, but keep the newlines.
*
* @param string $field
* @param string|null $string
*
* @return string
* @return string|null
*/
public function nlString(string $field): string
protected function nlStringFromValue(?string $string): ?string
{
return app('steam')->nlCleanString((string)($this->get($field) ?? ''));
if (null === $string) {
return null;
}
$result = app('steam')->nlCleanString($string);
return '' === $result ? null : $result;
}
/**
@@ -254,39 +277,6 @@ trait ConvertsDataTypes
return app('steam')->nlCleanString((string)($this->get($field) ?? ''));
}
/**
* @param string $value
*
* @return bool
*/
protected function convertBoolean(?string $value): bool
{
if (null === $value) {
return false;
}
if ('' === $value) {
return false;
}
if ('true' === $value) {
return true;
}
if ('yes' === $value) {
return true;
}
if (1 === $value) {
return true;
}
if ('1' === $value) {
return true;
}
if (true === $value) {
return true;
}
return false;
}
/**
* Return string value, or NULL if empty.
*
@@ -308,14 +298,19 @@ trait ConvertsDataTypes
}
/**
* Return string value.
* Parse and clean a string.
*
* @param string $field
* @param string|null $string
*
* @return string
* @return string|null
*/
public function string(string $field): string
protected function stringFromValue(?string $string): ?string
{
return app('steam')->cleanString((string)($this->get($field) ?? ''));
if (null === $string) {
return null;
}
$result = app('steam')->cleanString($string);
return '' === $result ? null : $result;
}
}

View File

@@ -69,6 +69,7 @@ trait GetRuleConfiguration
$return[] = $key;
}
}
return $return;
}
}

View File

@@ -61,7 +61,7 @@ class AccountSearch implements GenericSearchInterface
public function search(): Collection
{
$searchQuery = $this->user->accounts()
$searchQuery = $this->user->accounts()
->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id')
->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id')
->whereIn('account_types.type', $this->types);

View File

@@ -86,21 +86,21 @@ class OperatorQuerySearch implements SearchInterface
private BillRepositoryInterface $billRepository;
private BudgetRepositoryInterface $budgetRepository;
private CategoryRepositoryInterface $categoryRepository;
private TagRepositoryInterface $tagRepository;
private CurrencyRepositoryInterface $currencyRepository;
private TransactionTypeRepositoryInterface $typeRepository;
private User $user;
private ParsedQuery $query;
private int $page;
private int $limit;
private array $words;
private array $validOperators;
private GroupCollectorInterface $collector;
private float $startTime;
private Collection $modifiers; // obsolete
private CurrencyRepositoryInterface $currencyRepository;
private Carbon $date;
private int $limit;
private Collection $modifiers;
private Collection $operators;
private string $originalQuery;
private Carbon $date;
private int $page;
private ParsedQuery $query;
private float $startTime;
private TagRepositoryInterface $tagRepository;
private TransactionTypeRepositoryInterface $typeRepository; // obsolete
private User $user;
private array $validOperators;
private array $words;
/**
* OperatorQuerySearch constructor.
@@ -146,14 +146,6 @@ class OperatorQuerySearch implements SearchInterface
return $this->operators;
}
/**
* @param Carbon $date
*/
public function setDate(Carbon $date): void
{
$this->date = $date;
}
/**
* @inheritDoc
* @codeCoverageIgnore
@@ -163,24 +155,6 @@ class OperatorQuerySearch implements SearchInterface
return implode(' ', $this->words);
}
/**
* @return array
*/
public function getWords(): array
{
return $this->words;
}
/**
* @inheritDoc
* @codeCoverageIgnore
*/
public function setPage(int $page): void
{
$this->page = $page;
$this->collector->setPage($this->page);
}
/**
* @inheritDoc
* @codeCoverageIgnore
@@ -231,6 +205,33 @@ class OperatorQuerySearch implements SearchInterface
return $this->collector->getPaginatedGroups();
}
/**
* @param Carbon $date
*/
public function setDate(Carbon $date): void
{
$this->date = $date;
}
/**
* @param int $limit
*/
public function setLimit(int $limit): void
{
$this->limit = $limit;
$this->collector->setLimit($this->limit);
}
/**
* @inheritDoc
* @codeCoverageIgnore
*/
public function setPage(int $page): void
{
$this->page = $page;
$this->collector->setPage($this->page);
}
/**
* @inheritDoc
* @codeCoverageIgnore
@@ -644,6 +645,28 @@ class OperatorQuerySearch implements SearchInterface
return true;
}
/**
* @param string $operator
*
* @return string
* @throws FireflyException
*/
public static function getRootOperator(string $operator): string
{
$config = config(sprintf('firefly.search.operators.%s', $operator));
if (null === $config) {
throw new FireflyException(sprintf('No configuration for search operator "%s"', $operator));
}
if (true === $config['alias']) {
Log::debug(sprintf('"%s" is an alias for "%s", so return that instead.', $operator, $config['alias_for']));
return $config['alias_for'];
}
Log::debug(sprintf('"%s" is not an alias.', $operator));
return $operator;
}
/**
* searchDirection: 1 = source (default), 2 = destination
* stringPosition: 1 = start (default), 2 = end, 3 = contains, 4 = is
@@ -709,7 +732,6 @@ class OperatorQuerySearch implements SearchInterface
$this->collector->$collectorMethod($filtered);
}
/**
* searchDirection: 1 = source (default), 2 = destination
* stringPosition: 1 = start (default), 2 = end, 3 = contains, 4 = is
@@ -787,6 +809,14 @@ class OperatorQuerySearch implements SearchInterface
$this->collector->$collectorMethod($filtered);
}
/**
* @return Account
*/
private function getCashAccount(): Account
{
return $this->accountRepository->getCashAccount();
}
/**
* @param string $value
*
@@ -809,28 +839,6 @@ class OperatorQuerySearch implements SearchInterface
return $result;
}
/**
* @param string $operator
*
* @return string
* @throws FireflyException
*/
public static function getRootOperator(string $operator): string
{
$config = config(sprintf('firefly.search.operators.%s', $operator));
if (null === $config) {
throw new FireflyException(sprintf('No configuration for search operator "%s"', $operator));
}
if (true === $config['alias']) {
Log::debug(sprintf('"%s" is an alias for "%s", so return that instead.', $operator, $config['alias_for']));
return $config['alias_for'];
}
Log::debug(sprintf('"%s" is not an alias.', $operator));
return $operator;
}
/**
* @param string $value
*
@@ -852,19 +860,10 @@ class OperatorQuerySearch implements SearchInterface
}
/**
* @param int $limit
* @return array
*/
public function setLimit(int $limit): void
public function getWords(): array
{
$this->limit = $limit;
$this->collector->setLimit($this->limit);
}
/**
* @return Account
*/
private function getCashAccount(): Account
{
return $this->accountRepository->getCashAccount();
return $this->words;
}
}

View File

@@ -47,16 +47,6 @@ interface SearchInterface
*/
public function getWordsAsString(): string;
/**
* @param int $page
*/
public function setPage(int $page): void;
/**
* @param int $limit
*/
public function setLimit(int $limit): void;
/**
* @return bool
*/
@@ -77,13 +67,23 @@ interface SearchInterface
*/
public function searchTransactions(): LengthAwarePaginator;
/**
* @param User $user
*/
public function setUser(User $user);
/**
* @param Carbon $date
*/
public function setDate(Carbon $date): void;
/**
* @param int $limit
*/
public function setLimit(int $limit): void;
/**
* @param int $page
*/
public function setPage(int $page): void;
/**
* @param User $user
*/
public function setUser(User $user);
}

View File

@@ -39,9 +39,10 @@ trait GeneratesInstallationId
protected function generateInstallationId(): void
{
try {
$config = app('fireflyconfig')->get('installation_id', null);
} catch(FireflyException $e) {
$config = app('fireflyconfig')->get('installation_id', null);
} catch (FireflyException $e) {
Log::info('Could not create or generate installation ID. Do not continue.');
return;
}
@@ -52,7 +53,7 @@ trait GeneratesInstallationId
if (null === $config) {
$uuid4 = Uuid::uuid4();
$uniqueId = (string) $uuid4;
$uniqueId = (string)$uuid4;
Log::info(sprintf('Created Firefly III installation ID %s', $uniqueId));
app('fireflyconfig')->set('installation_id', $uniqueId);
}

View File

@@ -36,58 +36,6 @@ class OAuthKeys
private const PRIVATE_KEY = 'oauth_private_key';
private const PUBLIC_KEY = 'oauth_public_key';
/**
*
*/
public static function generateKeys(): void
{
Artisan::registerCommand(new KeysCommand());
Artisan::call('passport:keys');
}
/**
* @return bool
*/
public static function hasKeyFiles(): bool
{
$private = storage_path('oauth-private.key');
$public = storage_path('oauth-public.key');
return file_exists($private) && file_exists($public);
}
/**
* @return bool
*/
public static function keysInDatabase(): bool
{
return app('fireflyconfig')->has(self::PRIVATE_KEY) && app('fireflyconfig')->has(self::PUBLIC_KEY);
}
/**
*
*/
public static function restoreKeysFromDB(): void
{
$privateContent = Crypt::decrypt(app('fireflyconfig')->get(self::PRIVATE_KEY)->data);
$publicContent = Crypt::decrypt(app('fireflyconfig')->get(self::PUBLIC_KEY)->data);
$private = storage_path('oauth-private.key');
$public = storage_path('oauth-public.key');
file_put_contents($private, $privateContent);
file_put_contents($public, $publicContent);
}
/**
*
*/
public static function storeKeysInDB(): void
{
$private = storage_path('oauth-private.key');
$public = storage_path('oauth-public.key');
app('fireflyconfig')->set(self::PRIVATE_KEY, Crypt::encrypt(file_get_contents($private)));
app('fireflyconfig')->set(self::PUBLIC_KEY, Crypt::encrypt(file_get_contents($public)));
}
/**
*
*/
@@ -109,4 +57,56 @@ class OAuthKeys
}
}
/**
* @return bool
*/
public static function keysInDatabase(): bool
{
return app('fireflyconfig')->has(self::PRIVATE_KEY) && app('fireflyconfig')->has(self::PUBLIC_KEY);
}
/**
* @return bool
*/
public static function hasKeyFiles(): bool
{
$private = storage_path('oauth-private.key');
$public = storage_path('oauth-public.key');
return file_exists($private) && file_exists($public);
}
/**
*
*/
public static function generateKeys(): void
{
Artisan::registerCommand(new KeysCommand());
Artisan::call('passport:keys');
}
/**
*
*/
public static function storeKeysInDB(): void
{
$private = storage_path('oauth-private.key');
$public = storage_path('oauth-public.key');
app('fireflyconfig')->set(self::PRIVATE_KEY, Crypt::encrypt(file_get_contents($private)));
app('fireflyconfig')->set(self::PUBLIC_KEY, Crypt::encrypt(file_get_contents($public)));
}
/**
*
*/
public static function restoreKeysFromDB(): void
{
$privateContent = Crypt::decrypt(app('fireflyconfig')->get(self::PRIVATE_KEY)->data);
$publicContent = Crypt::decrypt(app('fireflyconfig')->get(self::PUBLIC_KEY)->data);
$private = storage_path('oauth-private.key');
$public = storage_path('oauth-public.key');
file_put_contents($private, $privateContent);
file_put_contents($public, $publicContent);
}
}

View File

@@ -25,9 +25,9 @@ namespace FireflyIII\Support\Twig;
use FireflyIII\Models\Account as AccountModel;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Twig\TwigFunction;
use Twig\TwigFilter;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;
/**
* Contains all amount formatting routines.
@@ -73,6 +73,22 @@ class AmountFormat extends AbstractExtension
);
}
/**
* @return TwigFilter
*/
protected function formatAmountPlain(): TwigFilter
{
return new TwigFilter(
'formatAmountPlain',
static function (string $string): string {
$currency = app('amount')->getDefaultCurrency();
return app('amount')->formatAnything($currency, $string, false);
},
['is_safe' => ['html']]
);
}
/**
* Will format the amount by the currency related to the given account.
*
@@ -96,24 +112,6 @@ class AmountFormat extends AbstractExtension
);
}
/**
* Will format the amount by the currency related to the given account.
*
* @return TwigFunction
*/
protected function formatAmountByCurrency(): TwigFunction
{
return new TwigFunction(
'formatAmountByCurrency',
static function (TransactionCurrency $currency, string $amount, bool $coloured = null): string {
$coloured = $coloured ?? true;
return app('amount')->formatAnything($currency, $amount, $coloured);
},
['is_safe' => ['html']]
);
}
/**
* Will format the amount by the currency related to the given account.
*
@@ -138,16 +136,18 @@ class AmountFormat extends AbstractExtension
}
/**
* @return TwigFilter
* Will format the amount by the currency related to the given account.
*
* @return TwigFunction
*/
protected function formatAmountPlain(): TwigFilter
protected function formatAmountByCurrency(): TwigFunction
{
return new TwigFilter(
'formatAmountPlain',
static function (string $string): string {
$currency = app('amount')->getDefaultCurrency();
return new TwigFunction(
'formatAmountByCurrency',
static function (TransactionCurrency $currency, string $amount, bool $coloured = null): string {
$coloured = $coloured ?? true;
return app('amount')->formatAnything($currency, $string, false);
return app('amount')->formatAnything($currency, $amount, $coloured);
},
['is_safe' => ['html']]
);

View File

@@ -72,109 +72,6 @@ class General extends AbstractExtension
];
}
protected function getRootSearchOperator(): TwigFunction
{
return new TwigFunction(
'getRootSearchOperator',
static function (string $operator): string {
return OperatorQuerySearch::getRootOperator($operator);
}
);
}
/**
* Will return "active" when a part of the route matches the argument.
* ie. "accounts" will match "accounts.index".
*
* @return TwigFunction
*/
protected function activeRoutePartial(): TwigFunction
{
return new TwigFunction(
'activeRoutePartial',
static function (): string {
$args = func_get_args();
$route = $args[0]; // name of the route.
$name = Route::getCurrentRoute()->getName() ?? '';
if (false !== strpos($name, $route)) {
return 'active';
}
return '';
}
);
}
/**
* Will return "menu-open" when a part of the route matches the argument.
* ie. "accounts" will match "accounts.index".
*
* @return TwigFunction
*/
protected function menuOpenRoutePartial(): TwigFunction
{
return new TwigFunction(
'menuOpenRoutePartial',
static function (): string {
$args = func_get_args();
$route = $args[0]; // name of the route.
$name = Route::getCurrentRoute()->getName() ?? '';
if (false !== strpos($name, $route)) {
return 'menu-open';
}
return '';
}
);
}
/**
* This function will return "active" when the current route matches the first argument (even partly)
* but, the variable $objectType has been set and matches the second argument.
*
* @return TwigFunction
*/
protected function activeRoutePartialObjectType(): TwigFunction
{
return new TwigFunction(
'activeRoutePartialObjectType',
static function ($context): string {
[, $route, $objectType] = func_get_args();
$activeObjectType = $context['objectType'] ?? false;
if ($objectType === $activeObjectType && false !== stripos(Route::getCurrentRoute()->getName(), $route)) {
return 'active';
}
return '';
},
['needs_context' => true]
);
}
/**
* Will return "active" when the current route matches the given argument
* exactly.
*
* @return TwigFunction
*/
protected function activeRouteStrict(): TwigFunction
{
return new TwigFunction(
'activeRouteStrict',
static function (): string {
$args = func_get_args();
$route = $args[0]; // name of the route.
if (Route::getCurrentRoute()->getName() === $route) {
return 'active';
}
return '';
}
);
}
/**
* Show account balance. Only used on the front page of Firefly III.
*
@@ -196,23 +93,6 @@ class General extends AbstractExtension
);
}
/**
* Formats a string as a thing by converting it to a Carbon first.
*
* @return TwigFunction
*/
protected function formatDate(): TwigFunction
{
return new TwigFunction(
'formatDate',
function (string $date, string $format): string {
$carbon = new Carbon($date);
return $carbon->formatLocalized($format);
}
);
}
/**
* Used to convert 1024 to 1kb etc.
*
@@ -238,79 +118,6 @@ class General extends AbstractExtension
);
}
/**
* @return TwigFunction
* @deprecated because it uses a query in a view
* TODO remove me.
*/
protected function getMetaField(): TwigFunction
{
return new TwigFunction(
'accountGetMetaField',
static function (Account $account, string $field): string {
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$result = $repository->getMetaValue($account, $field);
if (null === $result) {
return '';
}
return $result;
}
);
}
/**
* Will return true if the user is of role X.
*
* @return TwigFunction
*/
protected function hasRole(): TwigFunction
{
return new TwigFunction(
'hasRole',
static function (string $role): bool {
$repository = app(UserRepositoryInterface::class);
if ($repository->hasRole(auth()->user(), $role)) {
return true;
}
return false;
}
);
}
/**
* @return TwigFilter
*/
protected function markdown(): TwigFilter
{
return new TwigFilter(
'markdown',
static function (string $text): string {
$environment = Environment::createCommonMarkEnvironment();
$environment->addExtension(new GithubFlavoredMarkdownExtension());
$converter = new CommonMarkConverter(['allow_unsafe_links' => false, 'max_nesting_level' => 3, 'html_input' => 'escape'], $environment);
return $converter->convertToHtml($text);
}, ['is_safe' => ['html']]
);
}
/**
* @return TwigFilter
*/
protected function floatval(): TwigFilter
{
return new TwigFilter(
'floatval',
static function ($value): float {
return (float)$value;
}
);
}
/**
* Show icon with attachment.
*
@@ -390,6 +197,37 @@ class General extends AbstractExtension
);
}
/**
* @return TwigFilter
*/
protected function markdown(): TwigFilter
{
return new TwigFilter(
'markdown',
static function (string $text): string {
$environment = Environment::createCommonMarkEnvironment();
$environment->addExtension(new GithubFlavoredMarkdownExtension());
$converter = new CommonMarkConverter(['allow_unsafe_links' => false, 'max_nesting_level' => 3, 'html_input' => 'escape'], $environment);
return $converter->convertToHtml($text);
}, ['is_safe' => ['html']]
);
}
/**
* @return TwigFilter
*/
protected function floatval(): TwigFilter
{
return new TwigFilter(
'floatval',
static function ($value): float {
return (float)$value;
}
);
}
/**
* Basic example thing for some views.
*
@@ -404,4 +242,166 @@ class General extends AbstractExtension
}
);
}
/**
* Will return "active" when the current route matches the given argument
* exactly.
*
* @return TwigFunction
*/
protected function activeRouteStrict(): TwigFunction
{
return new TwigFunction(
'activeRouteStrict',
static function (): string {
$args = func_get_args();
$route = $args[0]; // name of the route.
if (Route::getCurrentRoute()->getName() === $route) {
return 'active';
}
return '';
}
);
}
/**
* Will return "active" when a part of the route matches the argument.
* ie. "accounts" will match "accounts.index".
*
* @return TwigFunction
*/
protected function activeRoutePartial(): TwigFunction
{
return new TwigFunction(
'activeRoutePartial',
static function (): string {
$args = func_get_args();
$route = $args[0]; // name of the route.
$name = Route::getCurrentRoute()->getName() ?? '';
if (false !== strpos($name, $route)) {
return 'active';
}
return '';
}
);
}
/**
* This function will return "active" when the current route matches the first argument (even partly)
* but, the variable $objectType has been set and matches the second argument.
*
* @return TwigFunction
*/
protected function activeRoutePartialObjectType(): TwigFunction
{
return new TwigFunction(
'activeRoutePartialObjectType',
static function ($context): string {
[, $route, $objectType] = func_get_args();
$activeObjectType = $context['objectType'] ?? false;
if ($objectType === $activeObjectType && false !== stripos(Route::getCurrentRoute()->getName(), $route)) {
return 'active';
}
return '';
},
['needs_context' => true]
);
}
/**
* Will return "menu-open" when a part of the route matches the argument.
* ie. "accounts" will match "accounts.index".
*
* @return TwigFunction
*/
protected function menuOpenRoutePartial(): TwigFunction
{
return new TwigFunction(
'menuOpenRoutePartial',
static function (): string {
$args = func_get_args();
$route = $args[0]; // name of the route.
$name = Route::getCurrentRoute()->getName() ?? '';
if (false !== strpos($name, $route)) {
return 'menu-open';
}
return '';
}
);
}
/**
* Formats a string as a thing by converting it to a Carbon first.
*
* @return TwigFunction
*/
protected function formatDate(): TwigFunction
{
return new TwigFunction(
'formatDate',
function (string $date, string $format): string {
$carbon = new Carbon($date);
return $carbon->formatLocalized($format);
}
);
}
/**
* @return TwigFunction
* @deprecated because it uses a query in a view
* TODO remove me.
*/
protected function getMetaField(): TwigFunction
{
return new TwigFunction(
'accountGetMetaField',
static function (Account $account, string $field): string {
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$result = $repository->getMetaValue($account, $field);
if (null === $result) {
return '';
}
return $result;
}
);
}
/**
* Will return true if the user is of role X.
*
* @return TwigFunction
*/
protected function hasRole(): TwigFunction
{
return new TwigFunction(
'hasRole',
static function (string $role): bool {
$repository = app(UserRepositoryInterface::class);
if ($repository->hasRole(auth()->user(), $role)) {
return true;
}
return false;
}
);
}
protected function getRootSearchOperator(): TwigFunction
{
return new TwigFunction(
'getRootSearchOperator',
static function (string $operator): string {
return OperatorQuerySearch::getRootOperator($operator);
}
);
}
}

View File

@@ -32,25 +32,15 @@ use Twig\TwigFunction;
class Rule extends AbstractExtension
{
/**
* @return TwigFunction
* @return array
*/
public function allActionTriggers(): TwigFunction
public function getFunctions(): array
{
return new TwigFunction(
'allRuleActions',
static function () {
// array of valid values for actions
$ruleActions = array_keys(Config::get('firefly.rule-actions'));
$possibleActions = [];
foreach ($ruleActions as $key) {
$possibleActions[$key] = (string)trans('firefly.rule_action_' . $key . '_choice');
}
unset($ruleActions);
asort($possibleActions);
return $possibleActions;
}
);
return [
$this->allJournalTriggers(),
$this->allRuleTriggers(),
$this->allActionTriggers(),
];
}
/**
@@ -93,14 +83,24 @@ class Rule extends AbstractExtension
}
/**
* @return array
* @return TwigFunction
*/
public function getFunctions(): array
public function allActionTriggers(): TwigFunction
{
return [
$this->allJournalTriggers(),
$this->allRuleTriggers(),
$this->allActionTriggers(),
];
return new TwigFunction(
'allRuleActions',
static function () {
// array of valid values for actions
$ruleActions = array_keys(Config::get('firefly.rule-actions'));
$possibleActions = [];
foreach ($ruleActions as $key) {
$possibleActions[$key] = (string)trans('firefly.rule_action_' . $key . '_choice');
}
unset($ruleActions);
asort($possibleActions);
return $possibleActions;
}
);
}
}

View File

@@ -29,7 +29,6 @@ use FireflyIII\Models\AccountType;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use Log;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
@@ -54,6 +53,226 @@ class TransactionGroupTwig extends AbstractExtension
];
}
/**
* Shows the amount for a single journal array.
*
* @return TwigFunction
*/
public function journalArrayAmount(): TwigFunction
{
return new TwigFunction(
'journalArrayAmount',
function (array $array): string {
// if is not a withdrawal, amount positive.
$result = $this->normalJournalArrayAmount($array);
// now append foreign amount, if any.
if (null !== $array['foreign_amount']) {
$foreign = $this->foreignJournalArrayAmount($array);
$result = sprintf('%s (%s)', $result, $foreign);
}
return $result;
},
['is_safe' => ['html']]
);
}
/**
* Generate normal amount for transaction from a transaction group.
*
* @param array $array
*
* @return string
*/
private function normalJournalArrayAmount(array $array): string
{
$type = $array['transaction_type_type'] ?? TransactionType::WITHDRAWAL;
$amount = $array['amount'] ?? '0';
$colored = true;
$sourceType = $array['source_account_type'] ?? 'invalid';
$amount = $this->signAmount($amount, $type, $sourceType);
if ($type === TransactionType::TRANSFER) {
$colored = false;
}
$result = app('amount')->formatFlat($array['currency_symbol'], (int)$array['currency_decimal_places'], $amount, $colored);
if ($type === TransactionType::TRANSFER) {
$result = sprintf('<span class="text-info">%s</span>', $result);
}
return $result;
}
/**
* @param string $amount
* @param string $transactionType
* @param string $sourceType
*
* @return string
*/
private function signAmount(string $amount, string $transactionType, string $sourceType): string
{
// withdrawals stay negative
if ($transactionType !== TransactionType::WITHDRAWAL) {
$amount = bcmul($amount, '-1');
}
// opening balance and it comes from initial balance? its expense.
if ($transactionType === TransactionType::OPENING_BALANCE && AccountType::INITIAL_BALANCE !== $sourceType) {
$amount = bcmul($amount, '-1');
}
// reconciliation and it comes from reconciliation?
if ($transactionType === TransactionType::RECONCILIATION && AccountType::RECONCILIATION !== $sourceType) {
$amount = bcmul($amount, '-1');
}
return $amount;
}
/**
* Generate foreign amount for transaction from a transaction group.
*
* @param array $array
*
* @return string
*/
private function foreignJournalArrayAmount(array $array): string
{
$type = $array['transaction_type_type'] ?? TransactionType::WITHDRAWAL;
$amount = $array['foreign_amount'] ?? '0';
$colored = true;
$sourceType = $array['source_account_type'] ?? 'invalid';
$amount = $this->signAmount($amount, $type, $sourceType);
if ($type === TransactionType::TRANSFER) {
$colored = false;
}
$result = app('amount')->formatFlat($array['foreign_currency_symbol'], (int)$array['foreign_currency_decimal_places'], $amount, $colored);
if ($type === TransactionType::TRANSFER) {
$result = sprintf('<span class="text-info">%s</span>', $result);
}
return $result;
}
/**
* Shows the amount for a single journal object.
*
* @return TwigFunction
*/
public function journalObjectAmount(): TwigFunction
{
return new TwigFunction(
'journalObjectAmount',
function (TransactionJournal $journal): string {
$result = $this->normalJournalObjectAmount($journal);
// now append foreign amount, if any.
if ($this->journalObjectHasForeign($journal)) {
$foreign = $this->foreignJournalObjectAmount($journal);
$result = sprintf('%s (%s)', $result, $foreign);
}
return $result;
},
['is_safe' => ['html']]
);
}
/**
* Generate normal amount for transaction from a transaction group.
*
* @param TransactionJournal $journal
*
* @return string
*/
private function normalJournalObjectAmount(TransactionJournal $journal): string
{
$type = $journal->transactionType->type;
$first = $journal->transactions()->where('amount', '<', 0)->first();
$currency = $journal->transactionCurrency;
$amount = $first->amount ?? '0';
$colored = true;
$sourceType = $first->account()->first()->accountType()->first()->type;
$amount = $this->signAmount($amount, $type, $sourceType);
if ($type === TransactionType::TRANSFER) {
$colored = false;
}
$result = app('amount')->formatFlat($currency->symbol, (int)$currency->decimal_places, $amount, $colored);
if ($type === TransactionType::TRANSFER) {
$result = sprintf('<span class="text-info">%s</span>', $result);
}
return $result;
}
/**
* @param TransactionJournal $journal
*
* @return bool
*/
private function journalObjectHasForeign(TransactionJournal $journal): bool
{
/** @var Transaction $first */
$first = $journal->transactions()->where('amount', '<', 0)->first();
return null !== $first->foreign_amount;
}
/**
* Generate foreign amount for journal from a transaction group.
*
* @param TransactionJournal $journal
*
* @return string
*/
private function foreignJournalObjectAmount(TransactionJournal $journal): string
{
$type = $journal->transactionType->type;
/** @var Transaction $first */
$first = $journal->transactions()->where('amount', '<', 0)->first();
$currency = $first->foreignCurrency;
$amount = $first->foreign_amount ?? '0';
$colored = true;
$sourceType = $first->account()->first()->accountType()->first()->type;
$amount = $this->signAmount($amount, $type, $sourceType);
if ($type === TransactionType::TRANSFER) {
$colored = false;
}
$result = app('amount')->formatFlat($currency->symbol, (int)$currency->decimal_places, $amount, $colored);
if ($type === TransactionType::TRANSFER) {
$result = sprintf('<span class="text-info">%s</span>', $result);
}
return $result;
}
/**
* @return TwigFunction
*/
public function journalHasMeta(): TwigFunction
{
return new TwigFunction(
'journalHasMeta',
static function (int $journalId, string $metaField) {
$count = DB::table('journal_meta')
->where('name', $metaField)
->where('transaction_journal_id', $journalId)
->whereNull('deleted_at')
->count();
return 1 === $count;
}
);
}
/**
* @return TwigFunction
*/
@@ -97,222 +316,4 @@ class TransactionGroupTwig extends AbstractExtension
}
);
}
/**
* @return TwigFunction
*/
public function journalHasMeta(): TwigFunction
{
return new TwigFunction(
'journalHasMeta',
static function (int $journalId, string $metaField) {
$count = DB::table('journal_meta')
->where('name', $metaField)
->where('transaction_journal_id', $journalId)
->whereNull('deleted_at')
->count();
return 1 === $count;
}
);
}
/**
* Shows the amount for a single journal array.
*
* @return TwigFunction
*/
public function journalArrayAmount(): TwigFunction
{
return new TwigFunction(
'journalArrayAmount',
function (array $array): string {
// if is not a withdrawal, amount positive.
$result = $this->normalJournalArrayAmount($array);
// now append foreign amount, if any.
if (null !== $array['foreign_amount']) {
$foreign = $this->foreignJournalArrayAmount($array);
$result = sprintf('%s (%s)', $result, $foreign);
}
return $result;
},
['is_safe' => ['html']]
);
}
/**
* Shows the amount for a single journal object.
*
* @return TwigFunction
*/
public function journalObjectAmount(): TwigFunction
{
return new TwigFunction(
'journalObjectAmount',
function (TransactionJournal $journal): string {
$result = $this->normalJournalObjectAmount($journal);
// now append foreign amount, if any.
if ($this->journalObjectHasForeign($journal)) {
$foreign = $this->foreignJournalObjectAmount($journal);
$result = sprintf('%s (%s)', $result, $foreign);
}
return $result;
},
['is_safe' => ['html']]
);
}
/**
* Generate foreign amount for transaction from a transaction group.
*
* @param array $array
*
* @return string
*/
private function foreignJournalArrayAmount(array $array): string
{
$type = $array['transaction_type_type'] ?? TransactionType::WITHDRAWAL;
$amount = $array['foreign_amount'] ?? '0';
$colored = true;
$sourceType = $array['source_account_type'] ?? 'invalid';
$amount = $this->signAmount($amount, $type, $sourceType);
if ($type === TransactionType::TRANSFER) {
$colored = false;
}
$result = app('amount')->formatFlat($array['foreign_currency_symbol'], (int) $array['foreign_currency_decimal_places'], $amount, $colored);
if ($type === TransactionType::TRANSFER) {
$result = sprintf('<span class="text-info">%s</span>', $result);
}
return $result;
}
/**
* Generate foreign amount for journal from a transaction group.
*
* @param TransactionJournal $journal
*
* @return string
*/
private function foreignJournalObjectAmount(TransactionJournal $journal): string
{
$type = $journal->transactionType->type;
/** @var Transaction $first */
$first = $journal->transactions()->where('amount', '<', 0)->first();
$currency = $first->foreignCurrency;
$amount = $first->foreign_amount ?? '0';
$colored = true;
$sourceType = $first->account()->first()->accountType()->first()->type;
$amount = $this->signAmount($amount, $type, $sourceType);
if ($type === TransactionType::TRANSFER) {
$colored = false;
}
$result = app('amount')->formatFlat($currency->symbol, (int) $currency->decimal_places, $amount, $colored);
if ($type === TransactionType::TRANSFER) {
$result = sprintf('<span class="text-info">%s</span>', $result);
}
return $result;
}
/**
* Generate normal amount for transaction from a transaction group.
*
* @param array $array
*
* @return string
*/
private function normalJournalArrayAmount(array $array): string
{
$type = $array['transaction_type_type'] ?? TransactionType::WITHDRAWAL;
$amount = $array['amount'] ?? '0';
$colored = true;
$sourceType = $array['source_account_type'] ?? 'invalid';
$amount = $this->signAmount($amount, $type, $sourceType);
if ($type === TransactionType::TRANSFER) {
$colored = false;
}
$result = app('amount')->formatFlat($array['currency_symbol'], (int) $array['currency_decimal_places'], $amount, $colored);
if ($type === TransactionType::TRANSFER) {
$result = sprintf('<span class="text-info">%s</span>', $result);
}
return $result;
}
/**
* Generate normal amount for transaction from a transaction group.
*
* @param TransactionJournal $journal
*
* @return string
*/
private function normalJournalObjectAmount(TransactionJournal $journal): string
{
$type = $journal->transactionType->type;
$first = $journal->transactions()->where('amount', '<', 0)->first();
$currency = $journal->transactionCurrency;
$amount = $first->amount ?? '0';
$colored = true;
$sourceType = $first->account()->first()->accountType()->first()->type;
$amount = $this->signAmount($amount, $type, $sourceType);
if ($type === TransactionType::TRANSFER) {
$colored = false;
}
$result = app('amount')->formatFlat($currency->symbol, (int) $currency->decimal_places, $amount, $colored);
if ($type === TransactionType::TRANSFER) {
$result = sprintf('<span class="text-info">%s</span>', $result);
}
return $result;
}
/**
* @param TransactionJournal $journal
* @return bool
*/
private function journalObjectHasForeign(TransactionJournal $journal): bool
{
/** @var Transaction $first */
$first = $journal->transactions()->where('amount', '<', 0)->first();
return null !== $first->foreign_amount;
}
/**
* @param string $amount
* @param string $transactionType
* @param string $sourceType
* @return string
*/
private function signAmount(string $amount, string $transactionType, string $sourceType): string
{
// withdrawals stay negative
if ($transactionType !== TransactionType::WITHDRAWAL) {
$amount = bcmul($amount, '-1');
}
// opening balance and it comes from initial balance? its expense.
if ($transactionType === TransactionType::OPENING_BALANCE && AccountType::INITIAL_BALANCE !== $sourceType) {
$amount = bcmul($amount, '-1');
}
// reconciliation and it comes from reconciliation?
if ($transactionType === TransactionType::RECONCILIATION && AccountType::RECONCILIATION !== $sourceType) {
$amount = bcmul($amount, '-1');
}
return $amount;
}
}