mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-10-25 05:03:13 +00:00
Code cleanup
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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'],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace FireflyIII\Support;
|
||||
|
||||
/**
|
||||
* Class ChartColour.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class ChartColour
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace FireflyIII\Support;
|
||||
|
||||
/**
|
||||
* Class Domain.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class Domain
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ use FireflyIII\User;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* Class Preferences.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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'),
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -28,6 +28,7 @@ use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Trait ApiSupport
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
trait ApiSupport
|
||||
|
||||
@@ -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'];
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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.';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ trait DateCalculation
|
||||
if ($start->lte($today) && $end->gte($today)) {
|
||||
$difference = $today->diffInDays($end);
|
||||
}
|
||||
|
||||
return 0 === $difference ? 1 : $difference;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.';
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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,
|
||||
];
|
||||
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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'],
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ trait GetRuleConfiguration
|
||||
$return[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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']]
|
||||
);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user