mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-10-12 23:45:10 +00:00
Merge remote-tracking branch 'upstream/develop' into fix-transfer-sign
This commit is contained in:
@@ -28,6 +28,7 @@ use FireflyIII\User;
|
||||
use Illuminate\Contracts\Encryption\DecryptException;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use NumberFormatter;
|
||||
|
||||
/**
|
||||
* Class Amount.
|
||||
@@ -36,7 +37,6 @@ use Log;
|
||||
*/
|
||||
class Amount
|
||||
{
|
||||
|
||||
/**
|
||||
* bool $sepBySpace is $localeconv['n_sep_by_space']
|
||||
* int $signPosn = $localeconv['n_sign_posn']
|
||||
@@ -111,6 +111,58 @@ 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.
|
||||
@@ -142,14 +194,15 @@ class Amount
|
||||
*/
|
||||
public function formatFlat(string $symbol, int $decimalPlaces, string $amount, bool $coloured = null): string
|
||||
{
|
||||
$locale = app('steam')->getLocale();
|
||||
|
||||
$coloured = $coloured ?? true;
|
||||
$float = round($amount, 12);
|
||||
$info = $this->getLocaleInfo();
|
||||
$formatted = number_format($float, $decimalPlaces, $info['mon_decimal_point'], $info['mon_thousands_sep']);
|
||||
$precedes = $amount < 0 ? $info['n_cs_precedes'] : $info['p_cs_precedes'];
|
||||
$separated = $amount < 0 ? $info['n_sep_by_space'] : $info['p_sep_by_space'];
|
||||
$space = true === $separated ? ' ' : '';
|
||||
$result = false === $precedes ? $formatted . $space . $symbol : $symbol . $space . $formatted;
|
||||
|
||||
$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($amount);
|
||||
|
||||
if (true === $coloured) {
|
||||
if ($amount > 0) {
|
||||
@@ -216,28 +269,7 @@ class Amount
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCurrencySymbol(): string
|
||||
{
|
||||
if ('testing' === config('app.env')) {
|
||||
Log::warning(sprintf('%s should NOT be called in the TEST environment!', __METHOD__));
|
||||
}
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty('getCurrencySymbol');
|
||||
if ($cache->has()) {
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
$currencyPreference = app('preferences')->get('currencyPreference', config('firefly.default_currency', 'EUR'));
|
||||
$currency = TransactionCurrency::where('code', $currencyPreference->data)->first();
|
||||
|
||||
$cache->store($currency->symbol);
|
||||
|
||||
return $currency->symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \FireflyIII\Models\TransactionCurrency
|
||||
* @return TransactionCurrency
|
||||
*/
|
||||
public function getDefaultCurrency(): TransactionCurrency
|
||||
{
|
||||
@@ -251,7 +283,7 @@ class Amount
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \FireflyIII\Models\TransactionCurrency
|
||||
* @return TransactionCurrency
|
||||
*/
|
||||
public function getSystemCurrency(): TransactionCurrency
|
||||
{
|
||||
@@ -265,7 +297,7 @@ class Amount
|
||||
/**
|
||||
* @param User $user
|
||||
*
|
||||
* @return \FireflyIII\Models\TransactionCurrency
|
||||
* @return TransactionCurrency
|
||||
*/
|
||||
public function getDefaultCurrencyByUser(User $user): TransactionCurrency
|
||||
{
|
||||
@@ -300,47 +332,6 @@ class Amount
|
||||
return $currency;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the correct format rules required by accounting.js,
|
||||
* the library used to format amounts in charts.
|
||||
*
|
||||
* @param array $config
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getJsConfig(array $config): array
|
||||
{
|
||||
$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 [
|
||||
'pos' => $positive,
|
||||
'neg' => $negative,
|
||||
'zero' => $positive,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public 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');
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $info
|
||||
* @param string $field
|
||||
|
139
app/Support/Authentication/RemoteUserGuard.php
Normal file
139
app/Support/Authentication/RemoteUserGuard.php
Normal file
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* RemoteUserGuard.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\Authentication;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
use Illuminate\Contracts\Auth\Guard;
|
||||
use Illuminate\Contracts\Auth\UserProvider;
|
||||
use Illuminate\Contracts\Foundation\Application;
|
||||
use Log;
|
||||
|
||||
|
||||
/**
|
||||
* Class RemoteUserGuard
|
||||
*/
|
||||
class RemoteUserGuard implements Guard
|
||||
{
|
||||
protected Application $application;
|
||||
protected $provider;
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* Create a new authentication guard.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\UserProvider $provider
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(UserProvider $provider, Application $app)
|
||||
{
|
||||
Log::debug('Constructed RemoteUserGuard');
|
||||
$this->application = $app;
|
||||
$this->provider = $provider;
|
||||
$this->user = null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function authenticate(): void
|
||||
{
|
||||
Log::debug(sprintf('Now at %s', __METHOD__));
|
||||
if (!is_null($this->user)) {
|
||||
Log::debug('No user found.');
|
||||
|
||||
return;
|
||||
}
|
||||
// Get the user identifier from $_SERVER
|
||||
$userID = request()->server('REMOTE_USER') ?? null;
|
||||
if (null === $userID) {
|
||||
Log::debug('No user in REMOTE_USER.');
|
||||
throw new FireflyException('The REMOTE_USER header was unexpectedly empty.');
|
||||
}
|
||||
|
||||
|
||||
// do some basic debugging here:
|
||||
// $userID = 'test@firefly';
|
||||
|
||||
/** @var User $user */
|
||||
$user = $this->provider->retrieveById($userID);
|
||||
|
||||
Log::debug(sprintf('Result of getting user from provider: %s', $user->email));
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function check(): bool
|
||||
{
|
||||
$result = !is_null($this->user());
|
||||
Log::debug(sprintf('Now in check(). Will return %s', var_export($result, true)));
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function guest(): bool
|
||||
{
|
||||
return !$this->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function id(): ?User
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function setUser(Authenticatable $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function user(): ?User
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function validate(array $credentials = [])
|
||||
{
|
||||
throw new FireflyException('Did not implement RemoteUserGuard::validate()');
|
||||
}
|
||||
}
|
100
app/Support/Authentication/RemoteUserProvider.php
Normal file
100
app/Support/Authentication/RemoteUserProvider.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* RemoteUserProvider.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\Authentication;
|
||||
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
use Illuminate\Contracts\Auth\UserProvider;
|
||||
use Illuminate\Foundation\Application;
|
||||
use Log;
|
||||
use Str;
|
||||
|
||||
/**
|
||||
* Class RemoteUserProvider
|
||||
*/
|
||||
class RemoteUserProvider implements UserProvider
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function retrieveByCredentials(array $credentials)
|
||||
{
|
||||
Log::debug(sprintf('Now at %s', __METHOD__));
|
||||
throw new FireflyException(sprintf('Did not implement %s', __METHOD__));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function retrieveById($identifier): User
|
||||
{
|
||||
Log::debug(sprintf('Now at %s(%s)', __METHOD__, $identifier));
|
||||
$user = User::where('email', $identifier)->first();
|
||||
if (null === $user) {
|
||||
Log::debug(sprintf('User with email "%s" not found. Will be created.', $identifier));
|
||||
$user = User::create(
|
||||
[
|
||||
'blocked' => false,
|
||||
'blocked_code' => null,
|
||||
'email' => $identifier,
|
||||
'password' => bcrypt(Str::random(64)),
|
||||
]
|
||||
);
|
||||
}
|
||||
Log::debug(sprintf('Going to return user #%d (%s)', $user->id, $user->email));
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function retrieveByToken($identifier, $token)
|
||||
{
|
||||
Log::debug(sprintf('Now at %s', __METHOD__));
|
||||
throw new FireflyException(sprintf('Did not implement %s', __METHOD__));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function updateRememberToken(Authenticatable $user, $token)
|
||||
{
|
||||
Log::debug(sprintf('Now at %s', __METHOD__));
|
||||
throw new FireflyException(sprintf('Did not implement %s', __METHOD__));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function validateCredentials(Authenticatable $user, array $credentials)
|
||||
{
|
||||
Log::debug(sprintf('Now at %s', __METHOD__));
|
||||
throw new FireflyException(sprintf('Did not implement %s', __METHOD__));
|
||||
}
|
||||
}
|
@@ -44,9 +44,7 @@ class AccountList implements BinderInterface
|
||||
*/
|
||||
public static function routeBinder(string $value, Route $route): Collection
|
||||
{
|
||||
//Log::debug(sprintf('Now in AccountList::routeBinder("%s")', $value));
|
||||
if (auth()->check()) {
|
||||
//Log::debug('User is logged in.');
|
||||
$collection = new Collection;
|
||||
if ('allAssetAccounts' === $value) {
|
||||
/** @var Collection $collection */
|
||||
@@ -65,7 +63,6 @@ class AccountList implements BinderInterface
|
||||
->whereIn('accounts.id', $list)
|
||||
->orderBy('accounts.name', 'ASC')
|
||||
->get(['accounts.*']);
|
||||
//Log::debug(sprintf('Collection length is %d', $collection->count()));
|
||||
}
|
||||
|
||||
if ($collection->count() > 0) {
|
||||
|
@@ -66,7 +66,6 @@ class BudgetList implements BinderInterface
|
||||
->where('active', 1)
|
||||
->whereIn('id', $list)
|
||||
->get();
|
||||
//Log::debug(sprintf('Found %d active budgets', $collection->count()), $list);
|
||||
|
||||
// add empty budget if applicable.
|
||||
if (in_array(0, $list, true)) {
|
||||
@@ -75,11 +74,9 @@ class BudgetList implements BinderInterface
|
||||
}
|
||||
|
||||
if ($collection->count() > 0) {
|
||||
//Log::debug(sprintf('List length is > 0 (%d), so return it.', $collection->count()));
|
||||
|
||||
return $collection;
|
||||
}
|
||||
//Log::debug('List length is zero, fall back to 404.');
|
||||
}
|
||||
Log::warning('BudgetList fallback to 404.');
|
||||
throw new NotFoundHttpException;
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* FrontpageChartGenerator.php
|
||||
* Copyright (c) 2020 thegrumpydictator@gmail.com
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\Chart\Category;
|
||||
|
||||
use Carbon\Carbon;
|
||||
@@ -87,18 +89,16 @@ class FrontpageChartGenerator
|
||||
foreach ($categories as $category) {
|
||||
// get expenses
|
||||
$collection[] = $this->collectExpenses($category, $accounts);
|
||||
$collection[] = $this->collectIncome($category, $accounts);
|
||||
}
|
||||
|
||||
// collect for no-category:
|
||||
$collection[] = $this->collectNoCatExpenses($accounts);
|
||||
$collection[] = $this->collectNoCatIncome($accounts);
|
||||
|
||||
$tempData = array_merge(...$collection);
|
||||
|
||||
// sort temp array by amount.
|
||||
$amounts = array_column($tempData, 'sum_float');
|
||||
array_multisort($amounts, SORT_DESC, $tempData);
|
||||
array_multisort($amounts, SORT_ASC, $tempData);
|
||||
|
||||
$currencyData = $this->createCurrencyGroups($tempData);
|
||||
|
||||
@@ -144,29 +144,6 @@ class FrontpageChartGenerator
|
||||
return $tempData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function collectIncome(Category $category, Collection $accounts): array
|
||||
{
|
||||
$spent = $this->opsRepos->sumIncome($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($currency['sum'], $currency['currency_decimal_places']),
|
||||
'currency_id' => (int) $currency['currency_id'],
|
||||
];
|
||||
}
|
||||
|
||||
return $tempData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $accounts
|
||||
*
|
||||
@@ -182,28 +159,8 @@ class FrontpageChartGenerator
|
||||
'name' => trans('firefly.no_category'),
|
||||
'sum' => $currency['sum'],
|
||||
'sum_float' => round($currency['sum'], $currency['currency_decimal_places'] ?? 2),
|
||||
'currency_id' => (int) $currency['currency_id'],];
|
||||
}
|
||||
|
||||
return $tempData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function collectNoCatIncome(Collection $accounts): array
|
||||
{
|
||||
$noCatExp = $this->noCatRepos->sumIncome($this->start, $this->end, $accounts);
|
||||
$tempData = [];
|
||||
foreach ($noCatExp as $currency) {
|
||||
$this->addCurrency($currency);
|
||||
$tempData[] = [
|
||||
'name' => trans('firefly.no_category'),
|
||||
'sum' => $currency['sum'],
|
||||
'sum_float' => round($currency['sum'], $currency['currency_decimal_places'] ?? 2),
|
||||
'currency_id' => (int) $currency['currency_id'],];
|
||||
'currency_id' => (int) $currency['currency_id'],
|
||||
];
|
||||
}
|
||||
|
||||
return $tempData;
|
||||
@@ -229,14 +186,6 @@ class FrontpageChartGenerator
|
||||
'currency_symbol' => $currency['currency_symbol'],
|
||||
'entries' => $names,
|
||||
];
|
||||
$key = sprintf('earned-%d', $currencyId);
|
||||
$return[$key] = [
|
||||
'label' => sprintf('%s (%s)', (string) trans('firefly.earned'), $currency['currency_name']),
|
||||
'type' => 'bar',
|
||||
'currency_symbol' => $currency['currency_symbol'],
|
||||
'data_type' => 'earned',
|
||||
'entries' => $names,
|
||||
];
|
||||
}
|
||||
|
||||
return $return;
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* AutoBudgetCronjob.php
|
||||
* Copyright (c) 2020 thegrumpydictator@gmail.com
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\Cronjobs;
|
||||
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* TelemetryCronjob.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\Cronjobs;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* ExportDataGenerator.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\Export;
|
||||
|
||||
use Carbon\Carbon;
|
||||
@@ -656,11 +658,11 @@ class ExportDataGenerator
|
||||
// TODO better place for keys?
|
||||
$header = ['user_id', 'group_id', 'journal_id', 'created_at', 'updated_at', 'group_title', 'type', 'amount', 'foreign_amount', 'currency_code',
|
||||
'foreign_currency_code', 'description', 'date', 'source_name', 'source_iban', 'source_type', 'destination_name', 'destination_iban',
|
||||
'destination_type', 'reconciled', 'category', 'budget', 'bill', 'tags',];
|
||||
'destination_type', 'reconciled', 'category', 'budget', 'bill', 'tags', 'notes'];
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setUser($this->user);
|
||||
$collector->setRange($this->start, $this->end)->withAccountInformation()->withCategoryInformation()->withBillInformation()
|
||||
->withBudgetInformation()->withTagInformation();
|
||||
->withBudgetInformation()->withTagInformation()->withNotes();
|
||||
$journals = $collector->getExtractedJournals();
|
||||
|
||||
$records = [];
|
||||
@@ -691,6 +693,7 @@ class ExportDataGenerator
|
||||
$journal['budget_name'],
|
||||
$journal['bill_name'],
|
||||
$this->mergeTags($journal['tags']),
|
||||
$journal['notes'],
|
||||
];
|
||||
|
||||
}
|
||||
|
@@ -38,7 +38,6 @@ use Illuminate\Support\Facades\Facade;
|
||||
* @method string getCurrencySymbol()
|
||||
* @method TransactionCurrency getDefaultCurrency()
|
||||
* @method TransactionCurrency getDefaultCurrencyByUser(User $user)
|
||||
* @method array getJsConfig(array $config)
|
||||
*/
|
||||
class Amount extends Facade
|
||||
{
|
||||
|
@@ -24,6 +24,7 @@ namespace FireflyIII\Support;
|
||||
|
||||
use Cache;
|
||||
use Exception;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Configuration;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Log;
|
||||
@@ -67,9 +68,10 @@ class FireflyConfig
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param mixed $default
|
||||
* @param null $default
|
||||
*
|
||||
* @return \FireflyIII\Models\Configuration|null
|
||||
* @throws FireflyException
|
||||
* @return Configuration|null
|
||||
*/
|
||||
public function get(string $name, $default = null): ?Configuration
|
||||
{
|
||||
@@ -82,9 +84,12 @@ class FireflyConfig
|
||||
}
|
||||
|
||||
try {
|
||||
/** @var Configuration $config */
|
||||
$config = Configuration::where('name', $name)->first(['id', 'name', 'data']);
|
||||
} catch (QueryException|Exception $e) {
|
||||
return null;
|
||||
//Log::error(sprintf('Query exception while polling for config var: %s', $e->getMessage()));
|
||||
//Log::error($e->getTraceAsString());
|
||||
throw new FireflyException(sprintf('Could not poll the database: %s', $e->getMessage()));
|
||||
}
|
||||
|
||||
if ($config) {
|
||||
@@ -151,7 +156,7 @@ class FireflyConfig
|
||||
if ('testing' === config('app.env')) {
|
||||
Log::warning(sprintf('%s should NOT be called in the TEST environment!', __METHOD__));
|
||||
}
|
||||
Log::debug('Set new value for ', ['name' => $name]);
|
||||
//Log::debug('Set new value for ', ['name' => $name]);
|
||||
/** @var Configuration $config */
|
||||
try {
|
||||
$config = Configuration::whereName($name)->first();
|
||||
@@ -163,7 +168,7 @@ class FireflyConfig
|
||||
return $item;
|
||||
}
|
||||
if (null === $config) {
|
||||
Log::debug('Does not exist yet ', ['name' => $name]);
|
||||
//Log::debug('Does not exist yet ', ['name' => $name]);
|
||||
/** @var Configuration $item */
|
||||
$item = new Configuration;
|
||||
$item->name = $name;
|
||||
@@ -174,7 +179,7 @@ class FireflyConfig
|
||||
|
||||
return $item;
|
||||
}
|
||||
Log::debug('Exists already, overwrite value.', ['name' => $name]);
|
||||
//Log::debug('Exists already, overwrite value.', ['name' => $name]);
|
||||
$config->data = $value;
|
||||
$config->save();
|
||||
Cache::forget('ff-config-' . $name);
|
||||
|
@@ -47,17 +47,43 @@ class PiggyBankForm
|
||||
*/
|
||||
public function piggyBankList(string $name, $value = null, array $options = null): string
|
||||
{
|
||||
|
||||
// make repositories
|
||||
/** @var PiggyBankRepositoryInterface $repository */
|
||||
$repository = app(PiggyBankRepositoryInterface::class);
|
||||
$piggyBanks = $repository->getPiggyBanksWithAmount();
|
||||
$array = [
|
||||
0 => (string)trans('firefly.none_in_select_list'),
|
||||
$title = (string) trans('firefly.default_group_title_name');
|
||||
$array = [];
|
||||
$subList = [
|
||||
0 => [
|
||||
'group' => [
|
||||
'title' => $title,
|
||||
],
|
||||
'piggies' => [
|
||||
(string) trans('firefly.none_in_select_list'),
|
||||
],
|
||||
],
|
||||
];
|
||||
/** @var PiggyBank $piggy */
|
||||
foreach ($piggyBanks as $piggy) {
|
||||
$array[$piggy->id] = $piggy->name;
|
||||
$group = $piggy->objectGroups->first();
|
||||
$groupTitle = null;
|
||||
$groupOrder = 0;
|
||||
if (null !== $group) {
|
||||
$groupTitle = $group->title;
|
||||
$groupOrder = $group->order;
|
||||
}
|
||||
$subList[$groupOrder] = $subList[$groupOrder] ?? [
|
||||
'group' => [
|
||||
'title' => $groupTitle,
|
||||
],
|
||||
'piggies' => [],
|
||||
];
|
||||
$subList[$groupOrder]['piggies'][$piggy->id] = $piggy->name;
|
||||
}
|
||||
ksort($subList);
|
||||
foreach ($subList as $info) {
|
||||
$groupTitle = $info['group']['title'];
|
||||
$array[$groupTitle] = $info['piggies'];
|
||||
}
|
||||
|
||||
return $this->select($name, $array, $value, $options);
|
||||
|
@@ -90,8 +90,8 @@ trait ChartGeneration
|
||||
$previous = array_values($range)[0];
|
||||
while ($currentStart <= $end) {
|
||||
$format = $currentStart->format('Y-m-d');
|
||||
$label = $currentStart->formatLocalized((string)trans('config.month_and_day', [], $locale));
|
||||
$balance = isset($range[$format]) ? round($range[$format], 12) : $previous;
|
||||
$label = trim($currentStart->formatLocalized((string)trans('config.month_and_day', [], $locale)));
|
||||
$balance = $range[$format] ?? $previous;
|
||||
$previous = $balance;
|
||||
$currentStart->addDay();
|
||||
$currentSet['entries'][$label] = $balance;
|
||||
|
@@ -106,12 +106,9 @@ trait GetConfigurationData
|
||||
// first range is the current range:
|
||||
$title => [$start, $end],
|
||||
];
|
||||
//Log::debug(sprintf('viewRange is %s', $viewRange));
|
||||
//Log::debug(sprintf('isCustom is %s', var_export($isCustom, true)));
|
||||
|
||||
// when current range is a custom range, add the current period as the next range.
|
||||
if ($isCustom) {
|
||||
//Log::debug('Custom is true.');
|
||||
$index = app('navigation')->periodShow($start, $viewRange);
|
||||
$customPeriodStart = app('navigation')->startOfPeriod($start, $viewRange);
|
||||
$customPeriodEnd = app('navigation')->endOfPeriod($customPeriodStart, $viewRange);
|
||||
|
@@ -166,7 +166,6 @@ trait RequestInformation
|
||||
// both must be array and either must be > 0
|
||||
if (count($intro) > 0 || count($specialIntro) > 0) {
|
||||
$shownDemo = app('preferences')->get($key, false)->data;
|
||||
//Log::debug(sprintf('Check if user has already seen intro with key "%s". Result is %s', $key, var_export($shownDemo, true)));
|
||||
}
|
||||
if (!is_bool($shownDemo)) {
|
||||
$shownDemo = true; // @codeCoverageIgnore
|
||||
|
@@ -40,10 +40,6 @@ use Log;
|
||||
trait UserNavigation
|
||||
{
|
||||
|
||||
//if (!$this->isEditableAccount($account)) {
|
||||
// return $this->redirectAccountToAccount($account); // @codeCoverageIgnore
|
||||
// }
|
||||
|
||||
/**
|
||||
* Will return false if you cant edit this account type.
|
||||
*
|
||||
|
@@ -539,7 +539,6 @@ class Navigation
|
||||
$subtract = $subtract ?? 1;
|
||||
$date = clone $theDate;
|
||||
// 1D 1W 1M 3M 6M 1Y
|
||||
//Log::debug(sprintf('subtractPeriod: date is %s, repeat frequency is %s and subtract is %d', $date->format('Y-m-d'), $repeatFreq, $subtract));
|
||||
$functionMap = [
|
||||
'1D' => 'subDays',
|
||||
'daily' => 'subDays',
|
||||
@@ -563,16 +562,12 @@ class Navigation
|
||||
if (isset($functionMap[$repeatFreq])) {
|
||||
$function = $functionMap[$repeatFreq];
|
||||
$date->$function($subtract);
|
||||
//Log::debug(sprintf('%s is in function map, execute %s with argument %d', $repeatFreq, $function, $subtract));
|
||||
//Log::debug(sprintf('subtractPeriod: resulting date is %s', $date->format('Y-m-d')));
|
||||
|
||||
return $date;
|
||||
}
|
||||
if (isset($modifierMap[$repeatFreq])) {
|
||||
$subtract *= $modifierMap[$repeatFreq];
|
||||
$date->subMonths($subtract);
|
||||
//Log::debug(sprintf('%s is in modifier map with value %d, execute subMonths with argument %d', $repeatFreq, $modifierMap[$repeatFreq], $subtract));
|
||||
//Log::debug(sprintf('subtractPeriod: resulting date is %s', $date->format('Y-m-d')));
|
||||
|
||||
return $date;
|
||||
}
|
||||
@@ -585,11 +580,8 @@ class Navigation
|
||||
/** @var Carbon $tEnd */
|
||||
$tEnd = session('end', Carbon::now()->endOfMonth());
|
||||
$diffInDays = $tStart->diffInDays($tEnd);
|
||||
//Log::debug(sprintf('repeatFreq is %s, start is %s and end is %s (session data).', $repeatFreq, $tStart->format('Y-m-d'), $tEnd->format('Y-m-d')));
|
||||
//Log::debug(sprintf('Diff in days is %d', $diffInDays));
|
||||
$date->subDays($diffInDays * $subtract);
|
||||
|
||||
//Log::debug(sprintf('subtractPeriod: resulting date is %s', $date->format('Y-m-d')));
|
||||
|
||||
return $date;
|
||||
}
|
||||
|
@@ -1,4 +1,25 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* ParseDateString.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
@@ -35,6 +56,7 @@ class ParseDateString
|
||||
*/
|
||||
public function parseDate(string $date): Carbon
|
||||
{
|
||||
$date = strtolower($date);
|
||||
// parse keywords:
|
||||
if (in_array($date, $this->keywords, true)) {
|
||||
return $this->parseKeyword($date);
|
||||
@@ -48,18 +70,189 @@ class ParseDateString
|
||||
|
||||
// if + or -:
|
||||
if (0 === strpos($date, '+') || 0 === strpos($date, '-')) {
|
||||
|
||||
return $this->parseRelativeDate($date);
|
||||
}
|
||||
if ('xxxx-xx-xx' === strtolower($date)) {
|
||||
throw new FireflyException(sprintf('[a]Not a recognised date format: "%s"', $date));
|
||||
}
|
||||
// can't do a partial year:
|
||||
$substrCount = substr_count(substr($date, 0, 4), 'x', 0);
|
||||
if (10 === strlen($date) && $substrCount > 0 && $substrCount < 4) {
|
||||
throw new FireflyException(sprintf('[b]Not a recognised date format: "%s"', $date));
|
||||
}
|
||||
|
||||
throw new FireflyException('Not recognised.');
|
||||
// maybe a date range
|
||||
if (10 === strlen($date) && (false !== strpos($date, 'xx') || false !== strpos($date, 'xxxx'))) {
|
||||
Log::debug(sprintf('[c]Detected a date range ("%s"), return a fake date.', $date));
|
||||
// very lazy way to parse the date without parsing it, because this specific function
|
||||
// cant handle date ranges.
|
||||
return new Carbon('1984-09-17');
|
||||
}
|
||||
|
||||
throw new FireflyException(sprintf('[d]Not a recognised date format: "%s"', $date));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $date
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isDateRange(string $date): bool
|
||||
{
|
||||
$date = strtolower($date);
|
||||
// not 10 chars:
|
||||
if (10 !== strlen($date)) {
|
||||
return false;
|
||||
}
|
||||
// all x'es
|
||||
if ('xxxx-xx-xx' === strtolower($date)) {
|
||||
return false;
|
||||
}
|
||||
// no x'es
|
||||
if (false === strpos($date, 'xx') && false === strpos($date, 'xxxx')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $date
|
||||
* @param Carbon $journalDate
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function parseRange(string $date, Carbon $journalDate): array
|
||||
{
|
||||
// several types of range can be submitted
|
||||
switch (true) {
|
||||
default:
|
||||
break;
|
||||
case $this->isDayRange($date):
|
||||
return $this->parseDayRange($date, $journalDate);
|
||||
case $this->isMonthRange($date):
|
||||
return $this->parseMonthRange($date, $journalDate);
|
||||
case $this->isYearRange($date):
|
||||
return $this->parseYearRange($date, $journalDate);
|
||||
case $this->isMonthDayRange($date):
|
||||
return $this->parseMonthDayRange($date, $journalDate);
|
||||
case $this->isDayYearRange($date):
|
||||
return $this->parseDayYearRange($date, $journalDate);
|
||||
case $this->isMonthYearRange($date):
|
||||
return $this->parseMonthYearRange($date, $journalDate);
|
||||
}
|
||||
|
||||
return [
|
||||
'start' => new Carbon('1984-09-17'),
|
||||
'end' => new Carbon('1984-09-17'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $date
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isDayRange(string $date): bool
|
||||
{
|
||||
// if regex for xxxx-xx-DD:
|
||||
$pattern = '/^xxxx-xx-(0[1-9]|[12][\d]|3[01])$/';
|
||||
if (preg_match($pattern, $date)) {
|
||||
Log::debug(sprintf('"%s" is a day range.', $date));
|
||||
|
||||
return true;
|
||||
}
|
||||
Log::debug(sprintf('"%s" is not a day range.', $date));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $date
|
||||
* @param Carbon $journalDate
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function parseDayRange(string $date, Carbon $journalDate): array
|
||||
{
|
||||
// format of string is xxxx-xx-DD
|
||||
$validDate = str_replace(['xxxx'], [$journalDate->year], $date);
|
||||
$validDate = str_replace(['xx'], [$journalDate->format('m')], $validDate);
|
||||
Log::debug(sprintf('parseDayRange: Parsed "%s" into "%s"', $date, $validDate));
|
||||
$start = Carbon::createFromFormat('Y-m-d', $validDate)->startOfDay();
|
||||
$end = Carbon::createFromFormat('Y-m-d', $validDate)->endOfDay();
|
||||
|
||||
return [
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $date
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isMonthRange(string $date): bool
|
||||
{
|
||||
// if regex for xxxx-MM-xx:
|
||||
$pattern = '/^xxxx-(0[1-9]|1[012])-xx$/';
|
||||
if (preg_match($pattern, $date)) {
|
||||
Log::debug(sprintf('"%s" is a month range.', $date));
|
||||
|
||||
return true;
|
||||
}
|
||||
Log::debug(sprintf('"%s" is not a month range.', $date));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $date
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isMonthYearRange(string $date): bool
|
||||
{
|
||||
// if regex for YYYY-MM-xx:
|
||||
$pattern = '/^(19|20)\d\d-(0[1-9]|1[012])-xx$/';
|
||||
if (preg_match($pattern, $date)) {
|
||||
Log::debug(sprintf('"%s" is a month/year range.', $date));
|
||||
|
||||
return true;
|
||||
}
|
||||
Log::debug(sprintf('"%s" is not a month/year range.', $date));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $date
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isYearRange(string $date): bool
|
||||
{
|
||||
// if regex for YYYY-xx-xx:
|
||||
$pattern = '/^(19|20)\d\d-xx-xx$/';
|
||||
if (preg_match($pattern, $date)) {
|
||||
Log::debug(sprintf('"%s" is a year range.', $date));
|
||||
|
||||
return true;
|
||||
}
|
||||
Log::debug(sprintf('"%s" is not a year range.', $date));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $date
|
||||
*
|
||||
* @return Carbon
|
||||
*/
|
||||
private function parseDefaultDate(string $date): Carbon
|
||||
protected function parseDefaultDate(string $date): Carbon
|
||||
{
|
||||
return Carbon::createFromFormat('Y-m-d', $date);
|
||||
}
|
||||
@@ -69,7 +262,7 @@ class ParseDateString
|
||||
*
|
||||
* @return Carbon
|
||||
*/
|
||||
private function parseKeyword(string $keyword): Carbon
|
||||
protected function parseKeyword(string $keyword): Carbon
|
||||
{
|
||||
$today = Carbon::today()->startOfDay();
|
||||
switch ($keyword) {
|
||||
@@ -99,12 +292,65 @@ class ParseDateString
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $date
|
||||
* @param Carbon $journalDate
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function parseMonthRange(string $date, Carbon $journalDate): array
|
||||
{
|
||||
// because 31 would turn February into March unexpectedly and the exact day is irrelevant here.
|
||||
$day = $journalDate->format('d');
|
||||
if ((int) $day > 28) {
|
||||
$day = '28';
|
||||
}
|
||||
|
||||
// format of string is xxxx-MM-xx
|
||||
$validDate = str_replace(['xxxx'], [$journalDate->year], $date);
|
||||
$validDate = str_replace(['xx'], [$day], $validDate);
|
||||
Log::debug(sprintf('parseMonthRange: Parsed "%s" into "%s"', $date, $validDate));
|
||||
$start = Carbon::createFromFormat('Y-m-d', $validDate)->startOfMonth();
|
||||
$end = Carbon::createFromFormat('Y-m-d', $validDate)->endOfMonth();
|
||||
|
||||
return [
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $date
|
||||
* @param Carbon $journalDate
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function parseMonthYearRange(string $date, Carbon $journalDate): array
|
||||
{
|
||||
// because 31 would turn February into March unexpectedly and the exact day is irrelevant here.
|
||||
$day = $journalDate->format('d');
|
||||
if ((int) $day > 28) {
|
||||
$day = '28';
|
||||
}
|
||||
|
||||
// format of string is YYYY-MM-xx
|
||||
$validDate = str_replace(['xx'], [$day], $date);
|
||||
Log::debug(sprintf('parseMonthYearRange: Parsed "%s" into "%s"', $date, $validDate));
|
||||
$start = Carbon::createFromFormat('Y-m-d', $validDate)->startOfMonth();
|
||||
$end = Carbon::createFromFormat('Y-m-d', $validDate)->endOfMonth();
|
||||
|
||||
return [
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $date
|
||||
*
|
||||
* @return Carbon
|
||||
*/
|
||||
private function parseRelativeDate(string $date): Carbon
|
||||
protected function parseRelativeDate(string $date): Carbon
|
||||
{
|
||||
Log::debug(sprintf('Now in parseRelativeDate("%s")', $date));
|
||||
$parts = explode(' ', $date);
|
||||
@@ -154,4 +400,106 @@ class ParseDateString
|
||||
return $today;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $date
|
||||
* @param Carbon $journalDate
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function parseYearRange(string $date, Carbon $journalDate): array
|
||||
{
|
||||
// format of string is YYYY-xx-xx
|
||||
// kind of a convulted way of replacing variables but I'm lazy.
|
||||
$validDate = str_replace(['xx-xx'], [sprintf('%s-xx', $journalDate->format('m'))], $date);
|
||||
$validDate = str_replace(['xx'], [$journalDate->format('d')], $validDate);
|
||||
Log::debug(sprintf('parseYearRange: Parsed "%s" into "%s"', $date, $validDate));
|
||||
$start = Carbon::createFromFormat('Y-m-d', $validDate)->startOfYear();
|
||||
$end = Carbon::createFromFormat('Y-m-d', $validDate)->endOfYear();
|
||||
|
||||
return [
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $date
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isMonthDayRange(string $date): bool
|
||||
{
|
||||
// if regex for xxxx-MM-DD:
|
||||
$pattern = '/^xxxx-(0[1-9]|1[012])-(0[1-9]|[12][\d]|3[01])$/';
|
||||
if (preg_match($pattern, $date)) {
|
||||
Log::debug(sprintf('"%s" is a month/day range.', $date));
|
||||
|
||||
return true;
|
||||
}
|
||||
Log::debug(sprintf('"%s" is not a month/day range.', $date));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $date
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isDayYearRange(string $date): bool
|
||||
{
|
||||
// if regex for YYYY-xx-DD:
|
||||
$pattern = '/^(19|20)\d\d-xx-(0[1-9]|[12][\d]|3[01])$/';
|
||||
if (preg_match($pattern, $date)) {
|
||||
Log::debug(sprintf('"%s" is a day/year range.', $date));
|
||||
|
||||
return true;
|
||||
}
|
||||
Log::debug(sprintf('"%s" is not a day/year range.', $date));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $date
|
||||
* @param Carbon $journalDate
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function parseMonthDayRange(string $date, Carbon $journalDate): array
|
||||
{
|
||||
// Any year.
|
||||
// format of string is xxxx-MM-DD
|
||||
$validDate = str_replace(['xxxx'], [$journalDate->year], $date);
|
||||
Log::debug(sprintf('parseMonthDayRange: Parsed "%s" into "%s"', $date, $validDate));
|
||||
$start = Carbon::createFromFormat('Y-m-d', $validDate)->startOfDay();
|
||||
$end = Carbon::createFromFormat('Y-m-d', $validDate)->endOfDay();
|
||||
|
||||
return [
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $date
|
||||
* @param Carbon $journalDate
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function parseDayYearRange(string $date, Carbon $journalDate): array
|
||||
{
|
||||
// Any year.
|
||||
// format of string is YYYY-xx-DD
|
||||
$validDate = str_replace(['xx'], [$journalDate->format('m')], $date);
|
||||
Log::debug(sprintf('parseDayYearRange: Parsed "%s" into "%s"', $date, $validDate));
|
||||
$start = Carbon::createFromFormat('Y-m-d', $validDate)->startOfDay();
|
||||
$end = Carbon::createFromFormat('Y-m-d', $validDate)->endOfDay();
|
||||
|
||||
return [
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -46,11 +46,11 @@ trait CalculateRangeOccurrences
|
||||
{
|
||||
$return = [];
|
||||
$attempts = 0;
|
||||
Log::debug('Rep is daily. Start of loop.');
|
||||
#Log::debug('Rep is daily. Start of loop.');
|
||||
while ($start <= $end) {
|
||||
Log::debug(sprintf('Mutator is now: %s', $start->format('Y-m-d')));
|
||||
#Log::debug(sprintf('Mutator is now: %s', $start->format('Y-m-d')));
|
||||
if (0 === $attempts % $skipMod) {
|
||||
Log::debug(sprintf('Attempts modulo skipmod is zero, include %s', $start->format('Y-m-d')));
|
||||
#Log::debug(sprintf('Attempts modulo skipmod is zero, include %s', $start->format('Y-m-d')));
|
||||
$return[] = clone $start;
|
||||
}
|
||||
$start->addDay();
|
||||
@@ -77,27 +77,27 @@ trait CalculateRangeOccurrences
|
||||
$return = [];
|
||||
$attempts = 0;
|
||||
$dayOfMonth = (int)$moment;
|
||||
Log::debug(sprintf('Day of month in repetition is %d', $dayOfMonth));
|
||||
Log::debug(sprintf('Start is %s.', $start->format('Y-m-d')));
|
||||
Log::debug(sprintf('End is %s.', $end->format('Y-m-d')));
|
||||
#Log::debug(sprintf('Day of month in repetition is %d', $dayOfMonth));
|
||||
#Log::debug(sprintf('Start is %s.', $start->format('Y-m-d')));
|
||||
#Log::debug(sprintf('End is %s.', $end->format('Y-m-d')));
|
||||
if ($start->day > $dayOfMonth) {
|
||||
Log::debug('Add a month.');
|
||||
#Log::debug('Add a month.');
|
||||
// day has passed already, add a month.
|
||||
$start->addMonth();
|
||||
}
|
||||
Log::debug(sprintf('Start is now %s.', $start->format('Y-m-d')));
|
||||
Log::debug('Start loop.');
|
||||
#Log::debug(sprintf('Start is now %s.', $start->format('Y-m-d')));
|
||||
#Log::debug('Start loop.');
|
||||
while ($start < $end) {
|
||||
Log::debug(sprintf('Mutator is now %s.', $start->format('Y-m-d')));
|
||||
#Log::debug(sprintf('Mutator is now %s.', $start->format('Y-m-d')));
|
||||
$domCorrected = min($dayOfMonth, $start->daysInMonth);
|
||||
Log::debug(sprintf('DoM corrected is %d', $domCorrected));
|
||||
#Log::debug(sprintf('DoM corrected is %d', $domCorrected));
|
||||
$start->day = $domCorrected;
|
||||
Log::debug(sprintf('Mutator is now %s.', $start->format('Y-m-d')));
|
||||
Log::debug(sprintf('$attempts %% $skipMod === 0 is %s', var_export(0 === $attempts % $skipMod, true)));
|
||||
Log::debug(sprintf('$start->lte($mutator) is %s', var_export($start->lte($start), true)));
|
||||
Log::debug(sprintf('$end->gte($mutator) is %s', var_export($end->gte($start), true)));
|
||||
#Log::debug(sprintf('Mutator is now %s.', $start->format('Y-m-d')));
|
||||
#Log::debug(sprintf('$attempts %% $skipMod === 0 is %s', var_export(0 === $attempts % $skipMod, true)));
|
||||
#Log::debug(sprintf('$start->lte($mutator) is %s', var_export($start->lte($start), true)));
|
||||
#Log::debug(sprintf('$end->gte($mutator) is %s', var_export($end->gte($start), true)));
|
||||
if (0 === $attempts % $skipMod && $start->lte($start) && $end->gte($start)) {
|
||||
Log::debug(sprintf('ADD %s to return!', $start->format('Y-m-d')));
|
||||
#Log::debug(sprintf('ADD %s to return!', $start->format('Y-m-d')));
|
||||
$return[] = clone $start;
|
||||
}
|
||||
$attempts++;
|
||||
|
153
app/Support/Request/AppendsLocationData.php
Normal file
153
app/Support/Request/AppendsLocationData.php
Normal file
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
/**
|
||||
* AppendsLocationData.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\Request;
|
||||
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Trait AppendsLocationData
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @param string|null $prefix
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function appendLocationData(array $data, ?string $prefix): array
|
||||
{
|
||||
Log::debug(sprintf('Now in appendLocationData("%s")', $prefix), $data);
|
||||
$data['store_location'] = false;
|
||||
$data['update_location'] = false;
|
||||
$data['longitude'] = null;
|
||||
$data['latitude'] = null;
|
||||
$data['zoom_level'] = null;
|
||||
|
||||
$longitudeKey = $this->getLocationKey($prefix, 'longitude');
|
||||
$latitudeKey = $this->getLocationKey($prefix, 'latitude');
|
||||
$zoomLevelKey = $this->getLocationKey($prefix, 'zoom_level');
|
||||
$hasLocationKey = $this->getLocationKey($prefix, 'has_location');
|
||||
$hasLocation = $this->boolean($hasLocationKey);
|
||||
|
||||
// for a POST (store), all fields must be present and accounted for:
|
||||
if (
|
||||
('POST' === $this->method() && $this->routeIs('*.store'))
|
||||
&& ($this->has($longitudeKey) && $this->has($latitudeKey) && $this->has($zoomLevelKey))
|
||||
) {
|
||||
Log::debug('Method is POST and all fields present.');
|
||||
$data['store_location'] = $this->boolean($hasLocationKey);
|
||||
$data['longitude'] = $this->nullableString($longitudeKey);
|
||||
$data['latitude'] = $this->nullableString($latitudeKey);
|
||||
$data['zoom_level'] = $this->nullableString($zoomLevelKey);
|
||||
}
|
||||
if (
|
||||
($this->has($longitudeKey) && $this->has($latitudeKey) && $this->has($zoomLevelKey))
|
||||
&& (
|
||||
('PUT' === $this->method() && $this->routeIs('*.update'))
|
||||
|| ('POST' === $this->method() && $this->routeIs('*.update'))
|
||||
)
|
||||
) {
|
||||
Log::debug('Method is PUT and all fields present.');
|
||||
$data['update_location'] = true;
|
||||
$data['longitude'] = $this->nullableString($longitudeKey);
|
||||
$data['latitude'] = $this->nullableString($latitudeKey);
|
||||
$data['zoom_level'] = $this->nullableString($zoomLevelKey);
|
||||
}
|
||||
if (false === $hasLocation || null === $data['longitude'] || null === $data['latitude'] || null === $data['zoom_level']) {
|
||||
Log::debug('One of the fields is NULL or hasLocation is false, wont save.');
|
||||
$data['store_location'] = false;
|
||||
$data['update_location'] = true; // update is always true, but the values are null:
|
||||
$data['longitude'] = null;
|
||||
$data['latitude'] = null;
|
||||
$data['zoom_level'] = null;
|
||||
}
|
||||
Log::debug(sprintf('Returning longitude: "%s", latitude: "%s", zoom level: "%s"', $data['longitude'], $data['latitude'], $data['zoom_level']));
|
||||
|
||||
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
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getLocationKey(?string $prefix, string $key): string
|
||||
{
|
||||
if (null === $prefix) {
|
||||
return $key;
|
||||
}
|
||||
|
||||
return sprintf('%s_%s', $prefix, $key);
|
||||
}
|
||||
|
||||
}
|
32
app/Support/Request/ConvertAPIDataTypes.php
Normal file
32
app/Support/Request/ConvertAPIDataTypes.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* ConvertAPIDataTypes.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\Request;
|
||||
|
||||
/**
|
||||
* Trait ConvertAPIDataTypes
|
||||
*/
|
||||
trait ConvertAPIDataTypes
|
||||
{
|
||||
|
||||
}
|
297
app/Support/Request/ConvertsDataTypes.php
Normal file
297
app/Support/Request/ConvertsDataTypes.php
Normal file
@@ -0,0 +1,297 @@
|
||||
<?php
|
||||
/**
|
||||
* ConvertsDataTypes.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\Request;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Trait ConvertsDataTypes
|
||||
*/
|
||||
trait ConvertsDataTypes
|
||||
{
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param string $field
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function integer(string $field): int
|
||||
{
|
||||
return (int) $this->get($field);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return floating value.
|
||||
*
|
||||
* @param string $field
|
||||
*
|
||||
* @return float|null
|
||||
*/
|
||||
protected function float(string $field): ?float
|
||||
{
|
||||
$res = $this->get($field);
|
||||
if (null === $res) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (float) $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse and clean a string, but keep the newlines.
|
||||
*
|
||||
* @param string|null $string
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function nlStringFromValue(?string $string): ?string
|
||||
{
|
||||
if (null === $string) {
|
||||
return null;
|
||||
}
|
||||
$result = app('steam')->nlCleanString($string);
|
||||
|
||||
return '' === $result ? null : $result;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $array
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
protected function arrayFromValue($array): ?array
|
||||
{
|
||||
if (is_array($array)) {
|
||||
return $array;
|
||||
}
|
||||
if (null === $array) {
|
||||
return null;
|
||||
}
|
||||
if (is_string($array)) {
|
||||
return explode(',', $array);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param string|null $string
|
||||
*
|
||||
* @return Carbon|null
|
||||
*/
|
||||
protected function dateFromValue(?string $string): ?Carbon
|
||||
{
|
||||
if (null === $string) {
|
||||
return null;
|
||||
}
|
||||
if ('' === $string) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
$carbon = new Carbon($string);
|
||||
} catch (Exception $e) {
|
||||
Log::debug(sprintf('Invalid date: %s: %s', $string, $e->getMessage()));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return $carbon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and clean a string.
|
||||
*
|
||||
* @param string|null $string
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function stringFromValue(?string $string): ?string
|
||||
{
|
||||
if (null === $string) {
|
||||
return null;
|
||||
}
|
||||
$result = app('steam')->cleanString($string);
|
||||
|
||||
return '' === $result ? null : $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse to integer
|
||||
*
|
||||
* @param string|null $string
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
protected function integerFromValue(?string $string): ?int
|
||||
{
|
||||
if (null === $string) {
|
||||
return null;
|
||||
}
|
||||
if ('' === $string) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (int) $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return string value, but keep newlines.
|
||||
*
|
||||
* @param string $field
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function nlString(string $field): string
|
||||
{
|
||||
return app('steam')->nlCleanString((string) ($this->get($field) ?? ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return integer value, or NULL when it's not set.
|
||||
*
|
||||
* @param string $field
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
protected function nullableInteger(string $field): ?int
|
||||
{
|
||||
if (!$this->has($field)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$value = (string) $this->get($field);
|
||||
if ('' === $value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (int) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return string value, but keep newlines, or NULL if empty.
|
||||
*
|
||||
* @param string $field
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function nullableNlString(string $field): ?string
|
||||
{
|
||||
if (!$this->has($field)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
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 ('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.
|
||||
*
|
||||
* @param string $field
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function nullableString(string $field): ?string
|
||||
{
|
||||
if (!$this->has($field)) {
|
||||
return null;
|
||||
}
|
||||
$res = trim(app('steam')->cleanString((string) ($this->get($field) ?? '')));
|
||||
if ('' === $res) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return string value.
|
||||
*
|
||||
* @param string $field
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function string(string $field): string
|
||||
{
|
||||
return app('steam')->cleanString((string) ($this->get($field) ?? ''));
|
||||
}
|
||||
}
|
63
app/Support/Request/GetRecurrenceData.php
Normal file
63
app/Support/Request/GetRecurrenceData.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
/**
|
||||
* GetRecurrenceData.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\Request;
|
||||
|
||||
/**
|
||||
* Trait GetRecurrenceData
|
||||
*/
|
||||
trait GetRecurrenceData
|
||||
{
|
||||
/**
|
||||
* @param array $transaction
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getSingleRecurrenceData(array $transaction): array
|
||||
{
|
||||
return [
|
||||
'amount' => $transaction['amount'],
|
||||
'currency_id' => isset($transaction['currency_id']) ? (int) $transaction['currency_id'] : null,
|
||||
'currency_code' => $transaction['currency_code'] ?? null,
|
||||
'foreign_amount' => $transaction['foreign_amount'] ?? null,
|
||||
'foreign_currency_id' => isset($transaction['foreign_currency_id']) ? (int) $transaction['foreign_currency_id'] : null,
|
||||
'foreign_currency_code' => $transaction['foreign_currency_code'] ?? null,
|
||||
'source_id' => isset($transaction['source_id']) ? (int) $transaction['source_id'] : null,
|
||||
'source_name' => isset($transaction['source_name']) ? (string) $transaction['source_name'] : null,
|
||||
'destination_id' => isset($transaction['destination_id']) ? (int) $transaction['destination_id'] : null,
|
||||
'destination_name' => isset($transaction['destination_name']) ? (string) $transaction['destination_name'] : null,
|
||||
'description' => $transaction['description'],
|
||||
'type' => $this->string('type'),
|
||||
|
||||
// new and updated fields:
|
||||
'piggy_bank_id' => isset($transaction['piggy_bank_id']) ? (int) $transaction['piggy_bank_id'] : null,
|
||||
'piggy_bank_name' => $transaction['piggy_bank_name'] ?? null,
|
||||
'tags' => $transaction['tags'] ?? [],
|
||||
'budget_id' => isset($transaction['budget_id']) ? (int) $transaction['budget_id'] : null,
|
||||
'budget_name' => $transaction['budget_name'] ?? null,
|
||||
'category_id' => isset($transaction['category_id']) ? (int) $transaction['category_id'] : null,
|
||||
'category_name' => $transaction['category_name'] ?? null,
|
||||
];
|
||||
}
|
||||
|
||||
}
|
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* AccountSearch.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\Search;
|
||||
|
||||
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* GenericSearchInterface.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\Search;
|
||||
|
||||
|
||||
|
@@ -102,7 +102,7 @@ class Search implements SearchInterface
|
||||
{
|
||||
$string = implode(' ', $this->words);
|
||||
if ('' === $string) {
|
||||
return \is_string($this->originalQuery) ? $this->originalQuery : '';
|
||||
return is_string($this->originalQuery) ? $this->originalQuery : '';
|
||||
}
|
||||
|
||||
return $string;
|
||||
@@ -132,6 +132,11 @@ class Search implements SearchInterface
|
||||
$filteredQuery = str_replace($match, '', $filteredQuery);
|
||||
}
|
||||
$filteredQuery = trim(str_replace(['"', "'"], '', $filteredQuery));
|
||||
|
||||
// str replace some stuff:
|
||||
$search = ['%', '=', '/', '<', '>', '(', ')', ';'];
|
||||
$filteredQuery = str_replace($search, ' ', $filteredQuery);
|
||||
|
||||
if ('' !== $filteredQuery) {
|
||||
$this->words = array_map('trim', explode(' ', $filteredQuery));
|
||||
}
|
||||
@@ -209,7 +214,7 @@ class Search implements SearchInterface
|
||||
case 'source':
|
||||
// source can only be asset, liability or revenue account:
|
||||
$searchTypes = [AccountType::ASSET, AccountType::MORTGAGE, AccountType::LOAN, AccountType::DEBT, AccountType::REVENUE];
|
||||
$accounts = $this->accountRepository->searchAccount($modifier['value'], $searchTypes);
|
||||
$accounts = $this->accountRepository->searchAccount($modifier['value'], $searchTypes, 25);
|
||||
if ($accounts->count() > 0) {
|
||||
$totalAccounts = $accounts->merge($totalAccounts);
|
||||
}
|
||||
@@ -218,19 +223,19 @@ class Search implements SearchInterface
|
||||
case 'destination':
|
||||
// source can only be asset, liability or expense account:
|
||||
$searchTypes = [AccountType::ASSET, AccountType::MORTGAGE, AccountType::LOAN, AccountType::DEBT, AccountType::EXPENSE];
|
||||
$accounts = $this->accountRepository->searchAccount($modifier['value'], $searchTypes);
|
||||
$accounts = $this->accountRepository->searchAccount($modifier['value'], $searchTypes, 25);
|
||||
if ($accounts->count() > 0) {
|
||||
$totalAccounts = $accounts->merge($totalAccounts);
|
||||
}
|
||||
break;
|
||||
case 'category':
|
||||
$result = $this->categoryRepository->searchCategory($modifier['value']);
|
||||
$result = $this->categoryRepository->searchCategory($modifier['value'], 25);
|
||||
if ($result->count() > 0) {
|
||||
$collector->setCategories($result);
|
||||
}
|
||||
break;
|
||||
case 'bill':
|
||||
$result = $this->billRepository->searchBill($modifier['value']);
|
||||
$result = $this->billRepository->searchBill($modifier['value'], 25);
|
||||
if ($result->count() > 0) {
|
||||
$collector->setBills($result);
|
||||
}
|
||||
@@ -243,7 +248,7 @@ class Search implements SearchInterface
|
||||
break;
|
||||
break;
|
||||
case 'budget':
|
||||
$result = $this->budgetRepository->searchBudget($modifier['value']);
|
||||
$result = $this->budgetRepository->searchBudget($modifier['value'], 25);
|
||||
if ($result->count() > 0) {
|
||||
$collector->setBudgets($result);
|
||||
}
|
||||
@@ -298,6 +303,12 @@ class Search implements SearchInterface
|
||||
$updatedAt = new Carbon($modifier['value']);
|
||||
$collector->setUpdatedAt($updatedAt);
|
||||
break;
|
||||
case 'external_id':
|
||||
$collector->setExternalId($modifier['value']);
|
||||
break;
|
||||
case 'internal_reference':
|
||||
$collector->setInternalReference($modifier['value']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$collector->setAccounts($totalAccounts);
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* TransactionSearch.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\Search;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* TransferSearch.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\Search;
|
||||
|
||||
|
||||
|
@@ -234,17 +234,17 @@ class Steam
|
||||
$modified = null === $entry->modified ? '0' : (string)$entry->modified;
|
||||
$foreignModified = null === $entry->modified_foreign ? '0' : (string)$entry->modified_foreign;
|
||||
$amount = '0';
|
||||
if ($currencyId === (int)$entry->transaction_currency_id || 0 === $currencyId) {
|
||||
if ($currencyId === (int) $entry->transaction_currency_id || 0 === $currencyId) {
|
||||
// use normal amount:
|
||||
$amount = $modified;
|
||||
}
|
||||
if ($currencyId === (int)$entry->foreign_currency_id) {
|
||||
if ($currencyId === (int) $entry->foreign_currency_id) {
|
||||
// use foreign amount:
|
||||
$amount = $foreignModified;
|
||||
}
|
||||
|
||||
$currentBalance = bcadd($currentBalance, $amount);
|
||||
$carbon = new Carbon($entry->date);
|
||||
$carbon = new Carbon($entry->date, config('app.timezone'));
|
||||
$date = $carbon->format('Y-m-d');
|
||||
$balances[$date] = $currentBalance;
|
||||
}
|
||||
@@ -362,8 +362,10 @@ class Steam
|
||||
* Remove weird chars from strings.
|
||||
*
|
||||
* @param string $string
|
||||
* TODO migrate to trait.
|
||||
*
|
||||
* @return string
|
||||
* @deprecated
|
||||
*/
|
||||
public function cleanString(string $string): string
|
||||
{
|
||||
@@ -425,8 +427,10 @@ class Steam
|
||||
* Remove weird chars from strings, but keep newlines and tabs.
|
||||
*
|
||||
* @param string $string
|
||||
* TODO migrate to trait.
|
||||
*
|
||||
* @return string
|
||||
* @deprecated
|
||||
*/
|
||||
public function nlCleanString(string $string): string
|
||||
{
|
||||
@@ -502,7 +506,9 @@ class Steam
|
||||
->get(['transactions.account_id', DB::raw('MAX(transaction_journals.date) AS max_date')]);
|
||||
|
||||
foreach ($set as $entry) {
|
||||
$list[(int)$entry->account_id] = new Carbon($entry->max_date);
|
||||
$date = new Carbon($entry->max_date,'UTC');
|
||||
$date->setTimezone(config('app.timezone'));
|
||||
$list[(int)$entry->account_id] = $date;
|
||||
}
|
||||
|
||||
return $list;
|
||||
@@ -619,6 +625,7 @@ class Steam
|
||||
return [
|
||||
sprintf('%s.utf8', $locale),
|
||||
sprintf('%s.UTF-8', $locale),
|
||||
str_replace('_', '-', $locale), // for Windows.
|
||||
];
|
||||
}
|
||||
|
||||
|
@@ -1,8 +1,30 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* GeneratesInstallationId.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\System;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use Log;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
|
||||
@@ -16,10 +38,21 @@ trait GeneratesInstallationId
|
||||
*/
|
||||
protected function generateInstallationId(): void
|
||||
{
|
||||
try {
|
||||
$config = app('fireflyconfig')->get('installation_id', null);
|
||||
} catch(FireflyException $e) {
|
||||
Log::info('Could not create or generate installation ID. Do not continue.');
|
||||
return;
|
||||
}
|
||||
|
||||
// delete if wrong UUID:
|
||||
if (null !== $config && 'b2c27d92-be90-5c10-8589-005df5b314e6' === $config->data) {
|
||||
$config = null;
|
||||
}
|
||||
|
||||
if (null === $config) {
|
||||
$uuid5 = Uuid::uuid5(Uuid::NAMESPACE_URL, 'firefly-iii.org');
|
||||
$uniqueId = (string) $uuid5;
|
||||
$uuid4 = Uuid::uuid4();
|
||||
$uniqueId = (string) $uuid4;
|
||||
Log::info(sprintf('Created Firefly III installation ID %s', $uniqueId));
|
||||
app('fireflyconfig')->set('installation_id', $uniqueId);
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* OAuthKeys.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\System;
|
||||
|
||||
use Artisan;
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Telemetry.php
|
||||
* Copyright (c) 2020 thegrumpydictator@gmail.com
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
@@ -60,6 +60,7 @@ class General extends AbstractExtension
|
||||
$this->activeRouteStrict(),
|
||||
$this->activeRoutePartial(),
|
||||
$this->activeRoutePartialObjectType(),
|
||||
$this->menuOpenRoutePartial(),
|
||||
$this->formatDate(),
|
||||
$this->getMetaField(),
|
||||
$this->hasRole(),
|
||||
@@ -89,9 +90,32 @@ class General extends AbstractExtension
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 $what has been set and matches the second argument.
|
||||
* but, the variable $objectType has been set and matches the second argument.
|
||||
*
|
||||
* @return TwigFunction
|
||||
*/
|
||||
|
@@ -286,6 +286,12 @@ class TransactionGroupTwig extends AbstractExtension
|
||||
$sourceAccountId = $journal['source_account_id'];
|
||||
$amount = $this->signAmount($amount, $type, $destinationType, $sourceAccountId, $account->id);
|
||||
|
||||
// withdrawals are negative
|
||||
if ($type !== TransactionType::WITHDRAWAL) {
|
||||
$amount = bcmul($amount, '-1');
|
||||
}
|
||||
|
||||
|
||||
if ($type === TransactionType::TRANSFER) {
|
||||
$colored = false;
|
||||
}
|
||||
@@ -345,9 +351,8 @@ class TransactionGroupTwig extends AbstractExtension
|
||||
$amount = bcmul($amount, '-1');
|
||||
}
|
||||
|
||||
// negative opening balance
|
||||
if ($type === TransactionType::OPENING_BALANCE)
|
||||
if (AccountType::INITIAL_BALANCE === $destinationType) {
|
||||
// opening balance and it goes to initial balance? its expense.
|
||||
if ($type === TransactionType::OPENING_BALANCE && AccountType::INITIAL_BALANCE === $destinationType) {
|
||||
$amount = bcmul($amount, '-1');
|
||||
}
|
||||
|
||||
@@ -357,6 +362,11 @@ class TransactionGroupTwig extends AbstractExtension
|
||||
$amount = bcmul($amount, '-1');
|
||||
}
|
||||
|
||||
// reconciliation and it goes to reconciliation?
|
||||
if ($type === TransactionType::RECONCILIATION && AccountType::RECONCILIATION === $destinationType) {
|
||||
$amount = bcmul($amount, '-1');
|
||||
}
|
||||
|
||||
return $amount;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user