Reset fix.

This commit is contained in:
James Cole
2026-01-13 20:32:42 +01:00
parent 95a6543a94
commit 858c44fbce
4 changed files with 102 additions and 96 deletions
@@ -24,7 +24,6 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use Illuminate\Http\Request;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\AccountTypeEnum;
@@ -37,6 +36,7 @@ use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Api\AccountFilter;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
/**
@@ -51,7 +51,7 @@ class AccountController extends Controller
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
/** @var array<int, string> */
private array $balanceTypes;
private array $balanceTypes;
private AccountRepositoryInterface $repository;
/**
@@ -60,16 +60,14 @@ class AccountController extends Controller
public function __construct()
{
parent::__construct();
$this->middleware(
function (Request $request, $next) {
$this->validateUserGroup($request);
$this->repository = app(AccountRepositoryInterface::class);
$this->repository->setUser($this->user);
$this->repository->setUserGroup($this->userGroup);
$this->middleware(function (Request $request, $next) {
$this->validateUserGroup($request);
$this->repository = app(AccountRepositoryInterface::class);
$this->repository->setUser($this->user);
$this->repository->setUserGroup($this->userGroup);
return $next($request);
}
);
return $next($request);
});
$this->balanceTypes = [AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value];
}
@@ -83,24 +81,18 @@ class AccountController extends Controller
public function accounts(AutocompleteApiRequest $request): JsonResponse
{
Log::debug('Before All.');
[
'types' => $types,
'query' => $query,
'date' => $date,
'limit' => $limit,
]
= $request->attributes->all();
['types' => $types, 'query' => $query, 'date' => $date, 'limit' => $limit] = $request->attributes->all();
$date ??= today(config('app.timezone'));
// set date to end-of-day for account balance. so it is at $date 23:59:59
$date->endOfDay();
$return = [];
$timer = Timer::getInstance();
$return = [];
$timer = Timer::getInstance();
$timer->start(sprintf('AC accounts "%s"', $query));
$result = $this->repository->searchAccount((string)$query, $types, $limit);
$allBalances = Steam::accountsBalancesOptimized($result, $date, $this->primaryCurrency, $this->convertToPrimary);
$result = $this->repository->searchAccount((string) $query, $types, $limit);
$allBalances = Steam::accountsBalancesOptimized($result, $date, $this->primaryCurrency, $this->convertToPrimary);
/** @var Account $account */
foreach ($result as $account) {
@@ -118,17 +110,17 @@ class AccountController extends Controller
}
$return[] = [
'id' => (string)$account->id,
'id' => (string) $account->id,
'name' => $account->name,
'name_with_balance' => $nameWithBalance,
'active' => $account->active,
'type' => $account->accountType->type,
'currency_id' => (string)$useCurrency->id,
'currency_id' => (string) $useCurrency->id,
'currency_name' => $useCurrency->name,
'currency_code' => $useCurrency->code,
'currency_symbol' => $useCurrency->symbol,
'currency_decimal_places' => $useCurrency->decimal_places,
'account_currency_id' => (string)$currency->id,
'account_currency_id' => (string) $currency->id,
'account_currency_name' => $currency->name,
'account_currency_code' => $currency->code,
'account_currency_symbol' => $currency->symbol,
@@ -137,16 +129,13 @@ class AccountController extends Controller
}
// custom order.
usort(
$return,
static function (array $left, array $right): int {
$order = [AccountTypeEnum::ASSET->value, AccountTypeEnum::REVENUE->value, AccountTypeEnum::EXPENSE->value];
$posA = (int)array_search($left['type'], $order, true);
$posB = (int)array_search($right['type'], $order, true);
usort($return, static function (array $left, array $right): int {
$order = [AccountTypeEnum::ASSET->value, AccountTypeEnum::REVENUE->value, AccountTypeEnum::EXPENSE->value];
$posA = (int) array_search($left['type'], $order, true);
$posB = (int) array_search($right['type'], $order, true);
return $posA - $posB;
}
);
return $posA - $posB;
});
$timer->stop(sprintf('AC accounts "%s"', $query));
return response()->api($return);
+32 -32
View File
@@ -24,9 +24,9 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use Deprecated;
use Carbon\Carbon;
use Carbon\Exceptions\InvalidFormatException;
use Deprecated;
use FireflyIII\Exceptions\BadHttpHeaderException;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Facades\Amount;
@@ -63,15 +63,16 @@ abstract class Controller extends BaseController
use ValidatesRequests;
use ValidatesUserGroupTrait;
protected const string CONTENT_TYPE = 'application/vnd.api+json';
protected const string JSON_CONTENT_TYPE = 'application/json';
protected array $accepts = ['application/json', 'application/vnd.api+json'];
protected const string CONTENT_TYPE = 'application/vnd.api+json';
protected const string JSON_CONTENT_TYPE = 'application/json';
protected bool $convertToPrimary = false;
protected array $accepts = ['application/json', 'application/vnd.api+json'];
protected bool $convertToPrimary = false;
protected TransactionCurrency $primaryCurrency;
/** @deprecated use Request classes */
protected ParameterBag $parameters;
protected ParameterBag $parameters;
/**
* Controller constructor.
@@ -79,26 +80,22 @@ abstract class Controller extends BaseController
public function __construct()
{
// get global parameters
$this->middleware(
function ($request, $next) {
$this->parameters = $this->getParameters();
if (auth()->check()) {
$language = Steam::getLanguage();
$this->convertToPrimary = Amount::convertToPrimary();
$this->primaryCurrency = Amount::getPrimaryCurrency();
app()->setLocale($language);
}
// filter down what this endpoint accepts.
if (!$request->accepts($this->accepts)) {
throw new BadHttpHeaderException(sprintf('Sorry, Accept header "%s" is not something this endpoint can provide.', $request->header('Accept')));
}
return $next($request);
$this->middleware(function ($request, $next) {
$this->parameters = $this->getParameters();
if (auth()->check()) {
$language = Steam::getLanguage();
$this->convertToPrimary = Amount::convertToPrimary();
$this->primaryCurrency = Amount::getPrimaryCurrency();
app()->setLocale($language);
}
);
// filter down what this endpoint accepts.
if (!$request->accepts($this->accepts)) {
throw new BadHttpHeaderException(sprintf('Sorry, Accept header "%s" is not something this endpoint can provide.', $request->header('Accept')));
}
return $next($request);
});
}
#[Deprecated(message: <<<'TXT'
@@ -108,7 +105,7 @@ abstract class Controller extends BaseController
private function getParameters(): ParameterBag
{
$bag = new ParameterBag();
$page = (int)request()->get('page');
$page = (int) request()->get('page');
$page = min(max(1, $page), 2 ** 16);
$bag->set('page', $page);
@@ -127,10 +124,10 @@ abstract class Controller extends BaseController
$obj = null;
if (null !== $date) {
try {
$obj = Carbon::parse((string)$date, config('app.timezone'));
$obj = Carbon::parse((string) $date, config('app.timezone'));
} catch (InvalidFormatException $e) {
// don't care
Log::warning(sprintf('Ignored invalid date "%s" in API controller parameter check: %s', substr((string)$date, 0, 20), $e->getMessage()));
Log::warning(sprintf('Ignored invalid date "%s" in API controller parameter check: %s', substr((string) $date, 0, 20), $e->getMessage()));
}
}
if ($obj instanceof Carbon) {
@@ -150,24 +147,27 @@ abstract class Controller extends BaseController
$value = null;
}
if (null !== $value) {
$value = (int)$value;
$value = (int) $value;
$value = min(max(1, $value), 2 ** 16);
$bag->set($integer, $value);
}
if (null === $value
if (
null === $value
&& 'limit' === $integer // @phpstan-ignore-line
&& auth()->check()) {
&& auth()->check()
) {
// set default for user:
/** @var User $user */
$user = auth()->user();
$pageSize = (int)Preferences::getForUser($user, 'listPageSize', 50)->data;
$pageSize = (int) Preferences::getForUser($user, 'listPageSize', 50)->data;
$bag->set($integer, $pageSize);
}
}
// sort fields:
return $bag;
// return $this->getSortParameters($bag);
}
@@ -32,9 +32,9 @@ use Illuminate\Support\Facades\Log;
class TransactionSummarizer
{
private bool $convertToPrimary = false;
private bool $convertToPrimary = false;
private TransactionCurrency $default;
private User $user;
private User $user;
public function __construct(?User $user = null)
{
@@ -51,7 +51,7 @@ class TransactionSummarizer
$field = 'amount';
// grab default currency information.
$currencyId = (int)$journal['currency_id'];
$currencyId = (int) $journal['currency_id'];
$currencyName = $journal['currency_name'];
$currencySymbol = $journal['currency_symbol'];
$currencyCode = $journal['currency_code'];
@@ -67,8 +67,8 @@ class TransactionSummarizer
if ($this->convertToPrimary) {
// Log::debug('convertToPrimary is true.');
// if convert to primary currency, use the primary currency amount yes or no?
$usePrimary = $this->default->id !== (int)$journal['currency_id'];
$useForeign = $this->default->id === (int)$journal['foreign_currency_id'];
$usePrimary = $this->default->id !== (int) $journal['currency_id'];
$useForeign = $this->default->id === (int) $journal['foreign_currency_id'];
if ($usePrimary) {
// Log::debug(sprintf('Journal #%d switches to primary currency amount (original is %s)', $journal['transaction_journal_id'], $journal['currency_code']));
$field = 'pc_amount';
@@ -81,7 +81,7 @@ class TransactionSummarizer
if ($useForeign) {
// Log::debug(sprintf('Journal #%d switches to foreign amount (foreign is %s)', $journal['transaction_journal_id'], $journal['foreign_currency_code']));
$field = 'foreign_amount';
$currencyId = (int)$journal['foreign_currency_id'];
$currencyId = (int) $journal['foreign_currency_id'];
$currencyName = $journal['foreign_currency_name'];
$currencySymbol = $journal['foreign_currency_symbol'];
$currencyCode = $journal['foreign_currency_code'];
@@ -91,9 +91,13 @@ class TransactionSummarizer
if (!$this->convertToPrimary) {
// Log::debug('convertToPrimary is false.');
// use foreign amount?
$foreignCurrencyId = (int)$journal['foreign_currency_id'];
$foreignCurrencyId = (int) $journal['foreign_currency_id'];
if (0 !== $foreignCurrencyId) {
Log::debug(sprintf('Journal #%d also includes foreign amount (foreign is "%s")', $journal['transaction_journal_id'], $journal['foreign_currency_code']));
Log::debug(sprintf(
'Journal #%d also includes foreign amount (foreign is "%s")',
$journal['transaction_journal_id'],
$journal['foreign_currency_code']
));
$foreignCurrencyName = $journal['foreign_currency_name'];
$foreignCurrencySymbol = $journal['foreign_currency_symbol'];
$foreignCurrencyCode = $journal['foreign_currency_code'];
@@ -102,10 +106,10 @@ class TransactionSummarizer
}
// first process normal amount
$amount = (string)($journal[$field] ?? '0');
$amount = (string) ($journal[$field] ?? '0');
$array[$currencyId] ??= [
'sum' => '0',
'currency_id' => (string) $currencyId,
'currency_id' => $currencyId,
'currency_name' => $currencyName,
'currency_symbol' => $currencySymbol,
'currency_code' => $currencyCode,
@@ -121,10 +125,10 @@ class TransactionSummarizer
// then process foreign amount, if it exists.
if (0 !== $foreignCurrencyId && $includeForeign) {
$amount = (string)($journal['foreign_amount'] ?? '0');
$amount = (string) ($journal['foreign_amount'] ?? '0');
$array[$foreignCurrencyId] ??= [
'sum' => '0',
'currency_id' => (string) $foreignCurrencyId,
'currency_id' => $foreignCurrencyId,
'currency_name' => $foreignCurrencyName,
'currency_symbol' => $foreignCurrencySymbol,
'currency_code' => $foreignCurrencyCode,
@@ -149,14 +153,12 @@ class TransactionSummarizer
public function groupByDirection(array $journals, string $method, string $direction): array
{
$array = [];
$idKey = sprintf('%s_account_id', $direction);
$nameKey = sprintf('%s_account_name', $direction);
$convertToPrimary = Amount::convertToPrimary($this->user);
$primary = Amount::getPrimaryCurrencyByUserGroup($this->user->userGroup);
Log::debug(sprintf('groupByDirection(array, %s, %s).', $direction, $method));
foreach ($journals as $journal) {
// currency
@@ -193,13 +195,25 @@ class TransactionSummarizer
];
// add the data from the $field to the array.
$array[$key]['sum'] = bcadd($array[$key]['sum'], (string) Steam::{$method}((string)($journal[$field] ?? '0'))); // @phpstan-ignore-line
Log::debug(sprintf('Field for transaction #%d is "%s" (%s). Sum: %s', $journal['transaction_group_id'], $currencyCode, $field, $array[$key]['sum']));
$array[$key]['sum'] = bcadd($array[$key]['sum'], (string) Steam::{$method}((string) ($journal[$field] ?? '0'))); // @phpstan-ignore-line
Log::debug(sprintf(
'Field for transaction #%d is "%s" (%s). Sum: %s',
$journal['transaction_group_id'],
$currencyCode,
$field,
$array[$key]['sum']
));
// also do foreign amount, but only when convertToPrimary is false (otherwise we have it already)
// or when convertToPrimary is true and the foreign currency is ALSO not the default currency.
if ((!$convertToPrimary || $journal['foreign_currency_id'] !== $primary->id) && 0 !== (int)$journal['foreign_currency_id']) {
Log::debug(sprintf('Use foreign amount from transaction #%d: %s %s. Sum: %s', $journal['transaction_group_id'], $currencyCode, $journal['foreign_amount'], $array[$key]['sum']));
if ((!$convertToPrimary || $journal['foreign_currency_id'] !== $primary->id) && 0 !== (int) $journal['foreign_currency_id']) {
Log::debug(sprintf(
'Use foreign amount from transaction #%d: %s %s. Sum: %s',
$journal['transaction_group_id'],
$currencyCode,
$journal['foreign_amount'],
$array[$key]['sum']
));
$key = sprintf('%s-%s', $journal[$idKey], $journal['foreign_currency_id']);
$array[$key] ??= [
'id' => $journal[$idKey],
@@ -211,7 +225,7 @@ class TransactionSummarizer
'currency_code' => $journal['foreign_currency_code'],
'currency_decimal_places' => $journal['foreign_currency_decimal_places'],
];
$array[$key]['sum'] = bcadd($array[$key]['sum'], (string) Steam::{$method}((string)$journal['foreign_amount'])); // @phpstan-ignore-line
$array[$key]['sum'] = bcadd($array[$key]['sum'], (string) Steam::{$method}((string) $journal['foreign_amount'])); // @phpstan-ignore-line
}
}
+14 -11
View File
@@ -24,9 +24,6 @@ declare(strict_types=1);
namespace FireflyIII;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\Support\Facades\Preferences;
use Illuminate\Support\Facades\Log;
use Deprecated;
use Exception;
use FireflyIII\Enums\UserRoleEnum;
@@ -57,6 +54,8 @@ use FireflyIII\Models\UserRole;
use FireflyIII\Models\Webhook;
use FireflyIII\Notifications\Admin\UserRegistration;
use FireflyIII\Notifications\Admin\VersionCheckResult;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
@@ -66,17 +65,20 @@ use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Str;
use Laravel\Passport\HasApiTokens;
use NotificationChannels\Pushover\PushoverReceiver;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use SensitiveParameter;
class User extends Authenticatable
{
use HasApiTokens;
use Notifiable;
use ReturnsIntegerIdTrait;
protected $fillable = ['email', 'password', 'blocked', 'blocked_code', 'user_group_id'];
protected $hidden = ['password', 'remember_token'];
protected $table = 'users';
@@ -258,7 +260,12 @@ class User extends Authenticatable
$dbRolesIds = $dbRoles->pluck('id')->toArray();
$dbRolesTitles = $dbRoles->pluck('title')->toArray();
$groupMemberships = $this->groupMemberships()->whereIn('user_role_id', $dbRolesIds)->where('user_group_id', $userGroup->id)->get();
$groupMemberships = $this
->groupMemberships()
->whereIn('user_role_id', $dbRolesIds)
->where('user_group_id', $userGroup->id)
->get()
;
if (0 === $groupMemberships->count()) {
Log::error(sprintf(
'User #%d "%s" does not have roles %s in user group #%d "%s"',
@@ -370,7 +377,7 @@ class User extends Authenticatable
return match ($driver) {
'mail' => $email,
default => null,
default => null
};
}
@@ -452,7 +459,7 @@ class User extends Authenticatable
*
* @param string $token
*/
public function sendPasswordResetNotification(#[\SensitiveParameter] $token): void
public function sendPasswordResetNotification(#[SensitiveParameter] $token): void
{
$ipAddress = Request::ip();
@@ -528,10 +535,6 @@ class User extends Authenticatable
protected function casts(): array
{
return [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'blocked' => 'boolean',
];
return ['created_at' => 'datetime', 'updated_at' => 'datetime', 'blocked' => 'boolean'];
}
}