Auto commit for release 'branch-v6.2' on 2024-12-14

This commit is contained in:
github-actions 2024-12-14 21:55:42 +01:00
parent 28d7e24d30
commit e2289ce1e6
54 changed files with 911 additions and 723 deletions

View File

@ -1,4 +1,5 @@
<?php
/*
* UserAttemptedLogin.php
* Copyright (c) 2024 james@firefly-iii.org.
@ -34,7 +35,7 @@ class UserAttemptedLogin extends Event
public User $user;
public function __construct(null | Authenticatable | User $user)
public function __construct(null|Authenticatable|User $user)
{
if ($user instanceof User) {
$this->user = $user;

View File

@ -32,7 +32,6 @@ use FireflyIII\Events\DetectedNewIPAddress;
use FireflyIII\Events\RegisteredUser;
use FireflyIII\Events\RequestedNewPassword;
use FireflyIII\Events\Security\UserAttemptedLogin;
use FireflyIII\Events\Test\OwnerTestNotificationChannel;
use FireflyIII\Events\Test\UserTestNotificationChannel;
use FireflyIII\Events\UserChangedEmail;
use FireflyIII\Exceptions\FireflyException;
@ -44,10 +43,6 @@ use FireflyIII\Models\UserGroup;
use FireflyIII\Models\UserRole;
use FireflyIII\Notifications\Admin\UserRegistration as AdminRegistrationNotification;
use FireflyIII\Notifications\Security\UserFailedLoginAttempt;
use FireflyIII\Notifications\Test\OwnerTestNotificationEmail;
use FireflyIII\Notifications\Test\OwnerTestNotificationNtfy;
use FireflyIII\Notifications\Test\OwnerTestNotificationPushover;
use FireflyIII\Notifications\Test\OwnerTestNotificationSlack;
use FireflyIII\Notifications\Test\UserTestNotificationEmail;
use FireflyIII\Notifications\Test\UserTestNotificationNtfy;
use FireflyIII\Notifications\Test\UserTestNotificationPushover;
@ -437,7 +432,8 @@ class UserEventHandler
}
}
public function sendLoginAttemptNotification(UserAttemptedLogin $event): void {
public function sendLoginAttemptNotification(UserAttemptedLogin $event): void
{
try {
Notification::send($event->user, new UserFailedLoginAttempt($event->user));
} catch (\Exception $e) { // @phpstan-ignore-line

View File

@ -39,6 +39,7 @@ class AccountObserver
{
app('log')->debug('Observe "deleting" of an account.');
$account->accountMeta()->delete();
/** @var PiggyBank $piggy */
foreach ($account->piggyBanks()->get() as $piggy) {
$piggy->accounts()->detach($account);

View File

@ -128,12 +128,12 @@ class LoginController extends Controller
}
app('log')->warning('Login attempt failed.');
$username = (string) $request->get($this->username());
$user = $this->repository->findByEmail($username);
$user = $this->repository->findByEmail($username);
if (null === $user) {
// send event to owner.
event(new UnknownUserAttemptedLogin($username));
}
if(null !== $user) {
if (null !== $user) {
event(new UserAttemptedLogin($user));
}

View File

@ -29,7 +29,6 @@ use Exception;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Middleware\IsDemoUser;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\Support\Http\Controllers\GetConfigurationData;
@ -282,10 +281,10 @@ class DebugController extends Controller
private function getUserFlags(): string
{
$flags = [];
$flags = [];
/** @var User $user */
$user = auth()->user();
$user = auth()->user();
// has liabilities
if ($user->accounts()->accountTypeIn([AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE])->count() > 0) {
@ -301,7 +300,7 @@ class DebugController extends Controller
}
// has stored reconciliations
$type = TransactionType::whereType(TransactionType::RECONCILIATION)->first();
$type = TransactionType::whereType(TransactionType::RECONCILIATION)->first();
if ($user->transactionJournals()->where('transaction_type_id', $type->id)->count() > 0) {
$flags[] = '<span title="Has reconciled">:ledger:</span>';
}

View File

@ -88,7 +88,7 @@ class AmountController extends Controller
];
$total = bcadd($total, $leftOnAccount);
}
$total = (float) $total; // intentional float.
$total = (float) $total; // intentional float.
return view('piggy-banks.add', compact('piggyBank', 'accounts', 'total'));
}
@ -130,9 +130,10 @@ class AmountController extends Controller
$amounts = $data['amount'] ?? [];
$total = '0';
Log::debug('Start with loop.');
/** @var Account $account */
foreach ($piggyBank->accounts as $account) {
$amount = (string) ($amounts[$account->id] ?? '0');
$amount = (string) ($amounts[$account->id] ?? '0');
if ('' === $amount || 0 === bccomp($amount, '0')) {
continue;
}
@ -148,7 +149,7 @@ class AmountController extends Controller
$amount = $leftToSave;
}
$canAddAmount = $this->piggyRepos->canAddAmount($piggyBank, $account, $amount);
$canAddAmount = $this->piggyRepos->canAddAmount($piggyBank, $account, $amount);
if ($canAddAmount) {
$this->piggyRepos->addAmount($piggyBank, $account, $amount);
$total = bcadd($total, $amount);
@ -182,7 +183,8 @@ class AmountController extends Controller
if (!is_array($amounts)) {
$amounts = [];
}
$total = '0';
$total = '0';
/** @var Account $account */
foreach ($piggyBank->accounts as $account) {
$amount = (string) ($amounts[$account->id] ?? '0');
@ -235,6 +237,7 @@ class AmountController extends Controller
'saved_so_far' => $this->piggyRepos->getCurrentAmount($piggyBank, $account),
];
}
return view('piggy-banks.remove', compact('piggyBank', 'accounts'));
}

View File

@ -81,15 +81,15 @@ class EditController extends Controller
$startDate = $piggyBank->start_date?->format('Y-m-d');
$preFilled = [
'name' => $piggyBank->name,
'name' => $piggyBank->name,
'target_amount' => app('steam')->bcround($piggyBank->target_amount, $piggyBank->transactionCurrency->decimal_places),
'target_date' => $targetDate,
'start_date' => $startDate,
'accounts' => [],
'object_group' => null !== $piggyBank->objectGroups->first() ? $piggyBank->objectGroups->first()->title : '',
'notes' => null === $note ? '' : $note->text,
'accounts' => [],
'object_group' => null !== $piggyBank->objectGroups->first() ? $piggyBank->objectGroups->first()->title : '',
'notes' => null === $note ? '' : $note->text,
];
foreach($piggyBank->accounts as $account) {
foreach ($piggyBank->accounts as $account) {
$preFilled['accounts'][] = $account->id;
}
if (0 === bccomp($piggyBank->target_amount, '0')) {

View File

@ -30,7 +30,6 @@ use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Preference;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Notifications\UrlValidator;
use FireflyIII\User;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
@ -69,9 +68,9 @@ class PreferencesController extends Controller
*/
public function index(AccountRepositoryInterface $repository)
{
$accounts = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]);
$isDocker = env('IS_DOCKER', false);
$groupedAccounts = [];
$accounts = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]);
$isDocker = env('IS_DOCKER', false);
$groupedAccounts = [];
/** @var Account $account */
foreach ($accounts as $account) {
@ -90,41 +89,41 @@ class PreferencesController extends Controller
ksort($groupedAccounts);
/** @var array<int, int> $accountIds */
$accountIds = $accounts->pluck('id')->toArray();
$viewRange = app('navigation')->getViewRange(false);
$frontpageAccountsPref = app('preferences')->get('frontpageAccounts', $accountIds);
$frontpageAccounts = $frontpageAccountsPref->data;
$accountIds = $accounts->pluck('id')->toArray();
$viewRange = app('navigation')->getViewRange(false);
$frontpageAccountsPref = app('preferences')->get('frontpageAccounts', $accountIds);
$frontpageAccounts = $frontpageAccountsPref->data;
if (!is_array($frontpageAccounts)) {
$frontpageAccounts = $accountIds;
}
$language = app('steam')->getLanguage();
$languages = config('firefly.languages');
$locale = app('preferences')->get('locale', config('firefly.default_locale', 'equal'))->data;
$listPageSize = app('preferences')->get('listPageSize', 50)->data;
$darkMode = app('preferences')->get('darkMode', 'browser')->data;
$customFiscalYear = app('preferences')->get('customFiscalYear', 0)->data;
$fiscalYearStartStr = app('preferences')->get('fiscalYearStart', '01-01')->data;
$language = app('steam')->getLanguage();
$languages = config('firefly.languages');
$locale = app('preferences')->get('locale', config('firefly.default_locale', 'equal'))->data;
$listPageSize = app('preferences')->get('listPageSize', 50)->data;
$darkMode = app('preferences')->get('darkMode', 'browser')->data;
$customFiscalYear = app('preferences')->get('customFiscalYear', 0)->data;
$fiscalYearStartStr = app('preferences')->get('fiscalYearStart', '01-01')->data;
if (is_array($fiscalYearStartStr)) {
$fiscalYearStartStr = '01-01';
}
$fiscalYearStart = sprintf('%s-%s', date('Y'), (string) $fiscalYearStartStr);
$tjOptionalFields = app('preferences')->get('transaction_journal_optional_fields', [])->data;
$availableDarkModes = config('firefly.available_dark_modes');
$fiscalYearStart = sprintf('%s-%s', date('Y'), (string) $fiscalYearStartStr);
$tjOptionalFields = app('preferences')->get('transaction_journal_optional_fields', [])->data;
$availableDarkModes = config('firefly.available_dark_modes');
// notifications settings
$slackUrl = app('preferences')->getEncrypted('slack_webhook_url', '')->data;
$pushoverAppToken = (string) app('preferences')->getEncrypted('pushover_app_token', '')->data;
$pushoverUserToken = (string) app('preferences')->getEncrypted('pushover_user_token', '')->data;
$ntfyServer = app('preferences')->getEncrypted('ntfy_server', 'https://ntfy.sh')->data;
$ntfyTopic = (string) app('preferences')->getEncrypted('ntfy_topic', '')->data;
$ntfyAuth = app('preferences')->get('ntfy_auth', false)->data;
$ntfyUser = app('preferences')->getEncrypted('ntfy_user', '')->data;
$ntfyPass = (string) app('preferences')->getEncrypted('ntfy_pass', '')->data;
$slackUrl = app('preferences')->getEncrypted('slack_webhook_url', '')->data;
$pushoverAppToken = (string) app('preferences')->getEncrypted('pushover_app_token', '')->data;
$pushoverUserToken = (string) app('preferences')->getEncrypted('pushover_user_token', '')->data;
$ntfyServer = app('preferences')->getEncrypted('ntfy_server', 'https://ntfy.sh')->data;
$ntfyTopic = (string) app('preferences')->getEncrypted('ntfy_topic', '')->data;
$ntfyAuth = app('preferences')->get('ntfy_auth', false)->data;
$ntfyUser = app('preferences')->getEncrypted('ntfy_user', '')->data;
$ntfyPass = (string) app('preferences')->getEncrypted('ntfy_pass', '')->data;
$channels = config('notifications.channels');
$forcedAvailability = [];
// notification preferences
$notifications = [];
$notifications = [];
foreach (config('notifications.notifications.user') as $key => $info) {
if ($info['enabled']) {
$notifications[$key]
@ -151,7 +150,7 @@ class PreferencesController extends Controller
app('log')->error($e->getMessage());
$locales = [];
}
$locales = ['equal' => (string) trans('firefly.equal_to_language')] + $locales;
$locales = ['equal' => (string) trans('firefly.equal_to_language')] + $locales;
// an important fallback is that the frontPageAccount array gets refilled automatically
// when it turns up empty.
if (0 === count($frontpageAccounts)) {
@ -342,6 +341,7 @@ class PreferencesController extends Controller
event(new UserTestNotificationChannel($channel, $user));
session()->flash('success', (string) trans('firefly.notification_test_executed', ['channel' => $channel]));
}
return '';
}
}

View File

@ -61,6 +61,7 @@ class PiggyBankUpdateRequest extends FormRequest
foreach ($accounts as $item) {
$data['accounts'][] = ['account_id' => (int) $item];
}
return $data;
}
@ -106,7 +107,7 @@ class PiggyBankUpdateRequest extends FormRequest
if ($accountCurrency->id !== $currency->id && 'true' !== $isMultiCurrency) {
$validator->errors()->add('accounts', trans('validation.invalid_account_currency'));
}
$type = $account->accountType->type;
$type = $account->accountType->type;
if (!in_array($type, $types, true)) {
$validator->errors()->add('accounts', trans('validation.invalid_account_type'));
}
@ -121,6 +122,7 @@ class PiggyBankUpdateRequest extends FormRequest
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray());
}
}
private function getCurrencyFromData(array $data): TransactionCurrency
{
$currencyId = (int) ($data['transaction_currency_id'] ?? 0);

View File

@ -1,4 +1,5 @@
<?php
/*
* PreferencesRequest.php
* Copyright (c) 2024 james@firefly-iii.org.
@ -31,7 +32,6 @@ class PreferencesRequest extends FormRequest
{
use ChecksLogin;
/**
* Rules for this request.
*/

View File

@ -84,6 +84,7 @@ class PiggyBank extends Model
{
return $this->belongsTo(TransactionCurrency::class);
}
public function account(): BelongsTo
{
throw new FireflyException('This method is not available on PiggyBank.');

View File

@ -61,7 +61,8 @@ class UnknownUserLoginAttempt extends Notification
{
return new MailMessage()
->markdown('emails.owner.unknown-user', ['address' => $this->address])
->subject((string) trans('email.unknown_user_subject'));
->subject((string) trans('email.unknown_user_subject'))
;
}
/**
@ -84,7 +85,8 @@ class UnknownUserLoginAttempt extends Notification
public function toPushover(OwnerNotifiable $notifiable): PushoverMessage
{
return PushoverMessage::create((string) trans('email.unknown_user_message', ['address' => $this->address]))
->title((string) trans('email.unknown_user_subject'));
->title((string) trans('email.unknown_user_subject'))
;
}
/**

View File

@ -46,7 +46,6 @@ class UserInvitation extends Notification
private InvitedUser $invitee;
private OwnerNotifiable $owner;
public function __construct(OwnerNotifiable $owner, InvitedUser $invitee)
{
$this->invitee = $invitee;
@ -69,7 +68,8 @@ class UserInvitation extends Notification
{
return (new MailMessage())
->markdown('emails.invitation-created', ['email' => $this->invitee->user->email, 'invitee' => $this->invitee->email])
->subject((string) trans('email.invitation_created_subject'));
->subject((string) trans('email.invitation_created_subject'))
;
}
/**
@ -95,7 +95,8 @@ class UserInvitation extends Notification
Log::debug('Now in toPushover() for UserInvitation');
return PushoverMessage::create((string) trans('email.invitation_created_body', ['email' => $this->invitee->user->email, 'invitee' => $this->invitee->email]))
->title((string) trans('email.invitation_created_subject'));
->title((string) trans('email.invitation_created_subject'))
;
}
/**

View File

@ -46,7 +46,6 @@ class UserRegistration extends Notification
private OwnerNotifiable $owner;
private User $user;
public function __construct(OwnerNotifiable $owner, User $user)
{
$this->user = $user;
@ -69,7 +68,8 @@ class UserRegistration extends Notification
{
return (new MailMessage())
->markdown('emails.registered-admin', ['email' => $this->user->email, 'id' => $this->user->id])
->subject((string) trans('email.registered_subject_admin'));
->subject((string) trans('email.registered_subject_admin'))
;
}
/**
@ -95,7 +95,8 @@ class UserRegistration extends Notification
Log::debug('Now in toPushover() for UserRegistration');
return PushoverMessage::create((string) trans('email.admin_new_user_registered', ['email' => $this->user->email, 'invitee' => $this->user->email]))
->title((string) trans('email.registered_subject_admin'));
->title((string) trans('email.registered_subject_admin'))
;
}
/**

View File

@ -44,7 +44,6 @@ class VersionCheckResult extends Notification
private string $message;
public function __construct(string $message)
{
$this->message = $message;
@ -66,7 +65,8 @@ class VersionCheckResult extends Notification
{
return (new MailMessage())
->markdown('emails.new-version', ['message' => $this->message])
->subject((string) trans('email.new_version_email_subject'));
->subject((string) trans('email.new_version_email_subject'))
;
}
/**
@ -92,7 +92,8 @@ class VersionCheckResult extends Notification
Log::debug('Now in toPushover() for VersionCheckResult');
return PushoverMessage::create($this->message)
->title((string) trans('email.new_version_email_subject'));
->title((string) trans('email.new_version_email_subject'))
;
}
/**
@ -101,9 +102,10 @@ class VersionCheckResult extends Notification
public function toSlack(OwnerNotifiable $notifiable)
{
return new SlackMessage()->content($this->message)
->attachment(static function ($attachment): void {
$attachment->title('Firefly III @ GitHub', 'https://github.com/firefly-iii/firefly-iii/releases');
});
->attachment(static function ($attachment): void {
$attachment->title('Firefly III @ GitHub', 'https://github.com/firefly-iii/firefly-iii/releases');
})
;
}
/**

View File

@ -41,7 +41,7 @@ class OwnerNotifiable
*/
public function routeNotificationFor($driver, $notification = null)
{
$method = 'routeNotificationFor' . Str::studly($driver);
$method = 'routeNotificationFor'.Str::studly($driver);
if (method_exists($this, $method)) {
Log::debug(sprintf('Redirect for settings to "%s".', $method));
@ -62,7 +62,8 @@ class OwnerNotifiable
$pushoverUserToken = (string) app('fireflyconfig')->getEncrypted('pushover_user_token', '')->data;
return PushoverReceiver::withUserKey($pushoverUserToken)
->withApplicationToken($pushoverAppToken);
->withApplicationToken($pushoverAppToken)
;
}
public function routeNotificationForSlack(): string

View File

@ -50,8 +50,8 @@ class ReturnsAvailableChannels
private static function returnOwnerChannels(): array
{
$channels = ['mail'];
$slackUrl = app('fireflyconfig')->getEncrypted('slack_webhook_url', '')->data;
$channels = ['mail'];
$slackUrl = app('fireflyconfig')->getEncrypted('slack_webhook_url', '')->data;
if (UrlValidator::isValidWebhookURL($slackUrl)) {
$channels[] = 'slack';
}
@ -83,8 +83,8 @@ class ReturnsAvailableChannels
private static function returnUserChannels(User $user): array
{
$channels = ['mail'];
$slackUrl = app('preferences')->getEncryptedForUser($user, 'slack_webhook_url', '')->data;
$channels = ['mail'];
$slackUrl = app('preferences')->getEncryptedForUser($user, 'slack_webhook_url', '')->data;
if (UrlValidator::isValidWebhookURL($slackUrl)) {
$channels[] = 'slack';
}

View File

@ -31,7 +31,6 @@ use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Log;
use NotificationChannels\Pushover\PushoverMessage;
use Ntfy\Message;
@ -82,7 +81,8 @@ class DisabledMFANotification extends Notification
public function toPushover(User $notifiable): PushoverMessage
{
return PushoverMessage::create((string) trans('email.disabled_mfa_slack', ['email' => $this->user->email]))
->title((string) trans('email.disabled_mfa_subject'));
->title((string) trans('email.disabled_mfa_subject'))
;
}
/**

View File

@ -40,7 +40,6 @@ class EnabledMFANotification extends Notification
private User $user;
public function __construct(User $user)
{
$this->user = $user;
@ -82,7 +81,8 @@ class EnabledMFANotification extends Notification
public function toPushover(User $notifiable): PushoverMessage
{
return PushoverMessage::create((string) trans('email.enabled_mfa_slack', ['email' => $this->user->email]))
->title((string) trans('email.enabled_mfa_subject'));
->title((string) trans('email.enabled_mfa_subject'))
;
}
/**
@ -95,7 +95,6 @@ class EnabledMFANotification extends Notification
return new SlackMessage()->content($message);
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/

View File

@ -93,10 +93,10 @@ class MFABackupFewLeftNotification extends Notification
public function toPushover(User $notifiable): PushoverMessage
{
return PushoverMessage::create((string) trans('email.mfa_few_backups_left_slack', ['email' => $this->user->email, 'count' => $this->count]))
->title((string) trans('email.mfa_few_backups_left_subject'));
->title((string) trans('email.mfa_few_backups_left_subject'))
;
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/

View File

@ -40,7 +40,6 @@ class MFABackupNoLeftNotification extends Notification
private User $user;
public function __construct(User $user)
{
$this->user = $user;
@ -92,10 +91,10 @@ class MFABackupNoLeftNotification extends Notification
public function toPushover(User $notifiable): PushoverMessage
{
return PushoverMessage::create((string) trans('email.mfa_few_backups_left_slack', ['email' => $this->user->email]))
->title((string) trans('email.mfa_no_backups_left_slack'));
->title((string) trans('email.mfa_no_backups_left_slack'))
;
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/

View File

@ -47,7 +47,6 @@ class MFAManyFailedAttemptsNotification extends Notification
$this->count = $count;
}
public function toArray(User $notifiable)
{
return [
@ -91,10 +90,10 @@ class MFAManyFailedAttemptsNotification extends Notification
public function toPushover(User $notifiable): PushoverMessage
{
return PushoverMessage::create((string) trans('email.mfa_many_failed_slack', ['email' => $this->user->email, 'count' => $this->count]))
->title((string) trans('email.mfa_many_failed_subject'));
->title((string) trans('email.mfa_many_failed_subject'))
;
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/

View File

@ -40,7 +40,6 @@ class MFAUsedBackupCodeNotification extends Notification
private User $user;
public function __construct(User $user)
{
$this->user = $user;
@ -92,7 +91,8 @@ class MFAUsedBackupCodeNotification extends Notification
public function toPushover(User $notifiable): PushoverMessage
{
return PushoverMessage::create((string) trans('email.used_backup_code_slack', ['email' => $this->user->email]))
->title((string) trans('email.used_backup_code_subject'));
->title((string) trans('email.used_backup_code_subject'))
;
}
/**

View File

@ -40,7 +40,6 @@ class NewBackupCodesNotification extends Notification
private User $user;
public function __construct(User $user)
{
$this->user = $user;
@ -92,7 +91,8 @@ class NewBackupCodesNotification extends Notification
public function toPushover(User $notifiable): PushoverMessage
{
return PushoverMessage::create((string) trans('email.new_backup_codes_slack', ['email' => $this->user->email]))
->title((string) trans('email.new_backup_codes_subject'));
->title((string) trans('email.new_backup_codes_subject'))
;
}
/**

View File

@ -1,4 +1,5 @@
<?php
/*
* UserFailedLoginAttempt.php
* Copyright (c) 2024 james@firefly-iii.org.
@ -39,13 +40,11 @@ class UserFailedLoginAttempt extends Notification
private User $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function toArray(User $notifiable)
{
return [
@ -89,7 +88,8 @@ class UserFailedLoginAttempt extends Notification
public function toPushover(User $notifiable): PushoverMessage
{
return PushoverMessage::create((string) trans('email.failed_login_message', ['email' => $this->user->email]))
->title((string) trans('email.failed_login_subject'));
->title((string) trans('email.failed_login_subject'))
;
}
/**

View File

@ -38,7 +38,6 @@ class OwnerTestNotificationEmail extends Notification
private OwnerNotifiable $owner;
public function __construct(OwnerNotifiable $owner)
{
$this->owner = $owner;
@ -62,7 +61,8 @@ class OwnerTestNotificationEmail extends Notification
return (new MailMessage())
->markdown('emails.admin-test', ['email' => $address])
->subject((string) trans('email.admin_test_subject'));
->subject((string) trans('email.admin_test_subject'))
;
}
/**

View File

@ -42,7 +42,6 @@ class OwnerTestNotificationNtfy extends Notification
public OwnerNotifiable $owner;
public function __construct(OwnerNotifiable $owner)
{
$this->owner = $owner;
@ -50,6 +49,8 @@ class OwnerTestNotificationNtfy extends Notification
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* @param mixed $notifiable
*/
public function toArray($notifiable)
{

View File

@ -42,7 +42,6 @@ class OwnerTestNotificationPushover extends Notification
private OwnerNotifiable $owner;
public function __construct(OwnerNotifiable $owner)
{
$this->owner = $owner;
@ -65,7 +64,8 @@ class OwnerTestNotificationPushover extends Notification
Log::debug('Now in toPushover()');
return PushoverMessage::create((string) trans('email.admin_test_message', ['channel' => 'Pushover']))
->title((string) trans('email.admin_test_subject'));
->title((string) trans('email.admin_test_subject'))
;
}
/**

View File

@ -40,7 +40,6 @@ class OwnerTestNotificationSlack extends Notification
private OwnerNotifiable $owner;
public function __construct(OwnerNotifiable $owner)
{
$this->owner = $owner;

View File

@ -38,7 +38,6 @@ class UserTestNotificationEmail extends Notification
private User $user;
public function __construct(User $user)
{
$this->user = $user;
@ -53,14 +52,14 @@ class UserTestNotificationEmail extends Notification
];
}
public function toMail(User $notifiable)
{
$address = (string) $notifiable->email;
return (new MailMessage())
->markdown('emails.admin-test', ['email' => $address])
->subject((string) trans('email.admin_test_subject'));
->subject((string) trans('email.admin_test_subject'))
;
}
/**

View File

@ -42,7 +42,6 @@ class UserTestNotificationNtfy extends Notification
public User $user;
public function __construct(User $user)
{
$this->user = $user;

View File

@ -42,7 +42,6 @@ class UserTestNotificationPushover extends Notification
private User $user;
public function __construct(User $user)
{
$this->user = $user;
@ -65,7 +64,8 @@ class UserTestNotificationPushover extends Notification
Log::debug('Now in (user) toPushover()');
return PushoverMessage::create((string) trans('email.admin_test_message', ['channel' => 'Pushover']))
->title((string) trans('email.admin_test_subject'));
->title((string) trans('email.admin_test_subject'))
;
}
/**

View File

@ -46,7 +46,6 @@ class BillReminder extends Notification
private int $diff;
private string $field;
public function __construct(Bill $bill, string $field, int $diff)
{
$this->bill = $bill;
@ -54,7 +53,6 @@ class BillReminder extends Notification
$this->diff = $diff;
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
@ -71,7 +69,8 @@ class BillReminder extends Notification
{
return (new MailMessage())
->markdown('emails.bill-warning', ['field' => $this->field, 'diff' => $this->diff, 'bill' => $this->bill])
->subject($this->getSubject());
->subject($this->getSubject())
;
}
/**
@ -87,7 +86,8 @@ class BillReminder extends Notification
->attachment(static function ($attachment) use ($bill, $url): void {
$attachment->title((string) trans('firefly.visit_bill', ['name' => $bill->name]), $url);
})
->content($this->getSubject());
->content($this->getSubject())
;
}
public function toNtfy(User $notifiable): Message
@ -107,7 +107,8 @@ class BillReminder extends Notification
public function toPushover(User $notifiable): PushoverMessage
{
return PushoverMessage::create((string) trans('email.bill_warning_please_action'))
->title($this->getSubject());
->title($this->getSubject())
;
}
private function getSubject(): string
@ -116,6 +117,7 @@ class BillReminder extends Notification
if (0 === $this->diff) {
$message = (string) trans(sprintf('email.bill_warning_subject_now_%s', $this->field), ['diff' => $this->diff, 'name' => $this->bill->name]);
}
return $message;
}

View File

@ -41,10 +41,8 @@ class NewAccessToken extends Notification
{
use Queueable;
public function __construct() {}
public function toArray(User $notifiable)
{
return [
@ -58,7 +56,8 @@ class NewAccessToken extends Notification
{
return (new MailMessage())
->markdown('emails.token-created')
->subject((string) trans('email.access_token_created_subject'));
->subject((string) trans('email.access_token_created_subject'))
;
}
/**
@ -86,7 +85,8 @@ class NewAccessToken extends Notification
public function toPushover(User $notifiable): PushoverMessage
{
return PushoverMessage::create((string) trans('email.access_token_created_body'))
->title((string) trans('email.access_token_created_subject'));
->title((string) trans('email.access_token_created_subject'))
;
}
/**

View File

@ -46,15 +46,14 @@ class RuleActionFailed extends Notification
private string $ruleLink;
private string $ruleTitle;
public function __construct(array $params)
{
[$mainMessage, $groupTitle, $groupLink, $ruleTitle, $ruleLink] = $params;
$this->message = $mainMessage;
$this->groupTitle = $groupTitle;
$this->groupLink = $groupLink;
$this->ruleTitle = $ruleTitle;
$this->ruleLink = $ruleLink;
$this->message = $mainMessage;
$this->groupTitle = $groupTitle;
$this->groupLink = $groupLink;
$this->ruleTitle = $ruleTitle;
$this->ruleLink = $ruleLink;
}
/**
@ -83,7 +82,6 @@ class RuleActionFailed extends Notification
});
}
public function toNtfy(User $notifiable): Message
{
$settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable);
@ -108,9 +106,10 @@ class RuleActionFailed extends Notification
public function via(User $notifiable)
{
$channels = ReturnsAvailableChannels::returnChannels('user', $notifiable);
if (($key = array_search('mail', $channels)) !== false) {
if (($key = array_search('mail', $channels, true)) !== false) {
unset($channels[$key]);
}
return $channels;
}
}

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\User;
use FireflyIII\Notifications\ReturnsAvailableChannels;
use FireflyIII\User;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
@ -39,7 +38,6 @@ class TransactionCreation extends Notification
private array $collection;
public function __construct(array $collection)
{
$this->collection = $collection;
@ -57,15 +55,14 @@ class TransactionCreation extends Notification
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function toMail(User $notifiable)
{
return (new MailMessage())
->markdown('emails.report-new-journals', ['transformed' => $this->collection])
->subject(trans_choice('email.new_journals_subject', count($this->collection)));
->subject(trans_choice('email.new_journals_subject', count($this->collection)))
;
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/

View File

@ -44,13 +44,11 @@ class UserLogin extends Notification
private string $ip;
public function __construct(string $ip)
{
$this->ip = $ip;
}
public function toArray(User $notifiable)
{
return [
@ -66,7 +64,8 @@ class UserLogin extends Notification
return (new MailMessage())
->markdown('emails.new-ip', ['time' => $time, 'ipAddress' => $this->ip, 'host' => $this->getHost()])
->subject((string) trans('email.login_from_new_ip'));
->subject((string) trans('email.login_from_new_ip'))
;
}
public function toNtfy(User $notifiable): Message
@ -86,7 +85,8 @@ class UserLogin extends Notification
public function toPushover(User $notifiable): PushoverMessage
{
return PushoverMessage::create((string) trans('email.slack_login_from_new_ip', ['host' => $this->getHost(), 'ip' => $this->ip]))
->title((string) trans('email.login_from_new_ip'));
->title((string) trans('email.login_from_new_ip'))
;
}
/**
@ -105,7 +105,8 @@ class UserLogin extends Notification
return ReturnsAvailableChannels::returnChannels('user', $notifiable);
}
private function getHost(): string {
private function getHost(): string
{
$host = '';
try {
@ -117,6 +118,7 @@ class UserLogin extends Notification
if ($hostName !== $this->ip) {
$host = $hostName;
}
return $host;
}
}

View File

@ -43,7 +43,6 @@ class UserNewPassword extends Notification
private string $url;
public function __construct(string $url)
{
$this->url = $url;
@ -65,7 +64,8 @@ class UserNewPassword extends Notification
{
return (new MailMessage())
->markdown('emails.password', ['url' => $this->url])
->subject((string) trans('email.reset_pw_subject'));
->subject((string) trans('email.reset_pw_subject'))
;
}
/**

View File

@ -36,7 +36,6 @@ class UserRegistration extends Notification
{
use Queueable;
public function __construct() {}
/**
@ -55,7 +54,8 @@ class UserRegistration extends Notification
{
return (new MailMessage())
->markdown('emails.registered', ['address' => route('index')])
->subject((string) trans('email.registered_subject'));
->subject((string) trans('email.registered_subject'))
;
}
/**

View File

@ -103,43 +103,43 @@ class EventServiceProvider extends ServiceProvider
protected $listen
= [
// is a User related event.
RegisteredUser::class => [
RegisteredUser::class => [
'FireflyIII\Handlers\Events\UserEventHandler@sendRegistrationMail',
'FireflyIII\Handlers\Events\UserEventHandler@sendAdminRegistrationNotification',
'FireflyIII\Handlers\Events\UserEventHandler@attachUserRole',
'FireflyIII\Handlers\Events\UserEventHandler@createGroupMembership',
'FireflyIII\Handlers\Events\UserEventHandler@createExchangeRates',
],
UserAttemptedLogin::class => [
UserAttemptedLogin::class => [
'FireflyIII\Handlers\Events\UserEventHandler@sendLoginAttemptNotification',
],
// is a User related event.
Login::class => [
Login::class => [
'FireflyIII\Handlers\Events\UserEventHandler@checkSingleUserIsAdmin',
'FireflyIII\Handlers\Events\UserEventHandler@demoUserBackToEnglish',
],
ActuallyLoggedIn::class => [
ActuallyLoggedIn::class => [
'FireflyIII\Handlers\Events\UserEventHandler@storeUserIPAddress',
],
DetectedNewIPAddress::class => [
DetectedNewIPAddress::class => [
'FireflyIII\Handlers\Events\UserEventHandler@notifyNewIPAddress',
],
RequestedVersionCheckStatus::class => [
RequestedVersionCheckStatus::class => [
'FireflyIII\Handlers\Events\VersionCheckEventHandler@checkForUpdates',
],
RequestedReportOnJournals::class => [
RequestedReportOnJournals::class => [
'FireflyIII\Handlers\Events\AutomationHandler@reportJournals',
],
// is a User related event.
RequestedNewPassword::class => [
RequestedNewPassword::class => [
'FireflyIII\Handlers\Events\UserEventHandler@sendNewPassword',
],
UserTestNotificationChannel::class => [
UserTestNotificationChannel::class => [
'FireflyIII\Handlers\Events\UserEventHandler@sendTestNotification',
],
// is a User related event.
UserChangedEmail::class => [
UserChangedEmail::class => [
'FireflyIII\Handlers\Events\UserEventHandler@sendEmailChangeConfirmMail',
'FireflyIII\Handlers\Events\UserEventHandler@sendEmailChangeUndoMail',
],
@ -147,104 +147,104 @@ class EventServiceProvider extends ServiceProvider
OwnerTestNotificationChannel::class => [
'FireflyIII\Handlers\Events\AdminEventHandler@sendTestNotification',
],
NewVersionAvailable::class => [
NewVersionAvailable::class => [
'FireflyIII\Handlers\Events\AdminEventHandler@sendNewVersion',
],
InvitationCreated::class => [
InvitationCreated::class => [
'FireflyIII\Handlers\Events\AdminEventHandler@sendInvitationNotification',
'FireflyIII\Handlers\Events\UserEventHandler@sendRegistrationInvite',
],
UnknownUserAttemptedLogin::class => [
UnknownUserAttemptedLogin::class => [
'FireflyIII\Handlers\Events\AdminEventHandler@sendLoginAttemptNotification',
],
// is a Transaction Journal related event.
StoredTransactionGroup::class => [
StoredTransactionGroup::class => [
'FireflyIII\Handlers\Events\StoredGroupEventHandler@processRules',
'FireflyIII\Handlers\Events\StoredGroupEventHandler@recalculateCredit',
'FireflyIII\Handlers\Events\StoredGroupEventHandler@triggerWebhooks',
],
// is a Transaction Journal related event.
UpdatedTransactionGroup::class => [
UpdatedTransactionGroup::class => [
'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@unifyAccounts',
'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@processRules',
'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@recalculateCredit',
'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@triggerWebhooks',
],
DestroyedTransactionGroup::class => [
DestroyedTransactionGroup::class => [
'FireflyIII\Handlers\Events\DestroyedGroupEventHandler@triggerWebhooks',
],
// API related events:
AccessTokenCreated::class => [
AccessTokenCreated::class => [
'FireflyIII\Handlers\Events\APIEventHandler@accessTokenCreated',
],
// Webhook related event:
RequestedSendWebhookMessages::class => [
RequestedSendWebhookMessages::class => [
'FireflyIII\Handlers\Events\WebhookEventHandler@sendWebhookMessages',
],
// account related events:
StoredAccount::class => [
StoredAccount::class => [
'FireflyIII\Handlers\Events\StoredAccountEventHandler@recalculateCredit',
],
UpdatedAccount::class => [
UpdatedAccount::class => [
'FireflyIII\Handlers\Events\UpdatedAccountEventHandler@recalculateCredit',
],
// bill related events:
WarnUserAboutBill::class => [
WarnUserAboutBill::class => [
'FireflyIII\Handlers\Events\BillEventHandler@warnAboutBill',
],
// audit log events:
TriggeredAuditLog::class => [
TriggeredAuditLog::class => [
'FireflyIII\Handlers\Events\AuditEventHandler@storeAuditEvent',
],
// piggy bank related events:
ChangedAmount::class => [
ChangedAmount::class => [
'FireflyIII\Handlers\Events\Model\PiggyBankEventHandler@changePiggyAmount',
],
// budget related events: CRUD budget limit
Created::class => [
Created::class => [
'FireflyIII\Handlers\Events\Model\BudgetLimitHandler@created',
],
Updated::class => [
Updated::class => [
'FireflyIII\Handlers\Events\Model\BudgetLimitHandler@updated',
],
Deleted::class => [
Deleted::class => [
'FireflyIII\Handlers\Events\Model\BudgetLimitHandler@deleted',
],
// rule actions
RuleActionFailedOnArray::class => [
RuleActionFailedOnArray::class => [
'FireflyIII\Handlers\Events\Model\RuleHandler@ruleActionFailedOnArray',
],
RuleActionFailedOnObject::class => [
RuleActionFailedOnObject::class => [
'FireflyIII\Handlers\Events\Model\RuleHandler@ruleActionFailedOnObject',
],
// security related
EnabledMFA::class => [
EnabledMFA::class => [
'FireflyIII\Handlers\Events\Security\MFAHandler@sendMFAEnabledMail',
],
DisabledMFA::class => [
DisabledMFA::class => [
'FireflyIII\Handlers\Events\Security\MFAHandler@sendMFADisabledMail',
],
MFANewBackupCodes::class => [
MFANewBackupCodes::class => [
'FireflyIII\Handlers\Events\Security\MFAHandler@sendNewMFABackupCodesMail',
],
MFAUsedBackupCode::class => [
MFAUsedBackupCode::class => [
'FireflyIII\Handlers\Events\Security\MFAHandler@sendUsedBackupCodeMail',
],
MFABackupFewLeft::class => [
MFABackupFewLeft::class => [
'FireflyIII\Handlers\Events\Security\MFAHandler@sendBackupFewLeftMail',
],
MFABackupNoLeft::class => [
MFABackupNoLeft::class => [
'FireflyIII\Handlers\Events\Security\MFAHandler@sendBackupNoLeftMail',
],
MFAManyFailedAttempts::class => [
MFAManyFailedAttempts::class => [
'FireflyIII\Handlers\Events\Security\MFAHandler@sendMFAFailedAttemptsMail',
],
];

View File

@ -57,10 +57,10 @@ trait ModifiesPiggyBanks
}
}
public function removeAmount(PiggyBank $piggyBank,Account $account, string $amount, ?TransactionJournal $journal = null): bool
public function removeAmount(PiggyBank $piggyBank, Account $account, string $amount, ?TransactionJournal $journal = null): bool
{
$currentAmount = $this->getCurrentAmount($piggyBank, $account);
$pivot = $piggyBank->accounts()->where('accounts.id', $account->id)->first()->pivot;
$currentAmount = $this->getCurrentAmount($piggyBank, $account);
$pivot = $piggyBank->accounts()->where('accounts.id', $account->id)->first()->pivot;
$pivot->current_amount = bcsub($currentAmount, $amount);
$pivot->save();
@ -72,11 +72,12 @@ trait ModifiesPiggyBanks
public function removeAmountFromAll(PiggyBank $piggyBank, string $amount): void
{
foreach($piggyBank->accounts as $account) {
foreach ($piggyBank->accounts as $account) {
$current = $account->pivot->current_amount;
// if this account contains more than the amount, remove the amount and return.
if (1 === bccomp($current, $amount)) {
$this->removeAmount($piggyBank, $account, $amount);
return;
}
// if this account contains less than the amount, remove the current amount, update the amount and continue.
@ -89,8 +90,8 @@ trait ModifiesPiggyBanks
public function addAmount(PiggyBank $piggyBank, Account $account, string $amount, ?TransactionJournal $journal = null): bool
{
$currentAmount = $this->getCurrentAmount($piggyBank, $account);
$pivot = $piggyBank->accounts()->where('accounts.id', $account->id)->first()->pivot;
$currentAmount = $this->getCurrentAmount($piggyBank, $account);
$pivot = $piggyBank->accounts()->where('accounts.id', $account->id)->first()->pivot;
$pivot->current_amount = bcadd($currentAmount, $amount);
$pivot->save();
@ -205,11 +206,12 @@ trait ModifiesPiggyBanks
// app('log')->debug(sprintf('Will move piggy bank #%d ("%s") from %d to %d', $piggyBank->id, $piggyBank->name, $oldOrder, $newOrder));
if ($newOrder > $oldOrder) {
PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', $this->user->id)
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', $this->user->id)
->where('piggy_banks.order', '<=', $newOrder)->where('piggy_banks.order', '>', $oldOrder)
->where('piggy_banks.id', '!=', $piggyBank->id)
->distinct()->decrement('piggy_banks.order');
->where('piggy_banks.id', '!=', $piggyBank->id)
->distinct()->decrement('piggy_banks.order')
;
$piggyBank->order = $newOrder;
app('log')->debug(sprintf('[1] Order of piggy #%d ("%s") from %d to %d', $piggyBank->id, $piggyBank->name, $oldOrder, $newOrder));
@ -218,11 +220,12 @@ trait ModifiesPiggyBanks
return true;
}
PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', $this->user->id)
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', $this->user->id)
->where('piggy_banks.order', '>=', $newOrder)->where('piggy_banks.order', '<', $oldOrder)
->where('piggy_banks.id', '!=', $piggyBank->id)
->distinct()->increment('piggy_banks.order');
->distinct()->increment('piggy_banks.order')
;
$piggyBank->order = $newOrder;
app('log')->debug(sprintf('[2] Order of piggy #%d ("%s") from %d to %d', $piggyBank->id, $piggyBank->name, $oldOrder, $newOrder));
@ -250,20 +253,20 @@ trait ModifiesPiggyBanks
public function update(PiggyBank $piggyBank, array $data): PiggyBank
{
$piggyBank = $this->updateProperties($piggyBank, $data);
$piggyBank = $this->updateProperties($piggyBank, $data);
if (array_key_exists('notes', $data)) {
$this->updateNote($piggyBank, (string)$data['notes']);
}
// update the order of the piggy bank:
$oldOrder = $piggyBank->order;
$newOrder = (int)($data['order'] ?? $oldOrder);
$oldOrder = $piggyBank->order;
$newOrder = (int)($data['order'] ?? $oldOrder);
if ($oldOrder !== $newOrder) {
$this->setOrder($piggyBank, $newOrder);
}
// update the accounts
$factory = new PiggyBankFactory();
$factory = new PiggyBankFactory();
$factory->user = $this->user;
$factory->linkToAccountIds($piggyBank, $data['accounts']);
@ -272,7 +275,7 @@ trait ModifiesPiggyBanks
// remove money from the rep.
$currentAmount = $this->getCurrentAmount($piggyBank);
if (1 === bccomp($currentAmount, '100') && 0 !== bccomp($piggyBank->target_amount, '0')) {
$difference = bcsub($piggyBank->target_amount, $currentAmount);
$difference = bcsub($piggyBank->target_amount, $currentAmount);
// an amount will be removed, create "negative" event:
event(new ChangedAmount($piggyBank, $difference, null, null));

View File

@ -96,7 +96,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
public function getAttachments(PiggyBank $piggyBank): Collection
{
$set = $piggyBank->attachments()->get();
$set = $piggyBank->attachments()->get();
/** @var \Storage $disk */
$disk = \Storage::disk('upload');
@ -119,7 +119,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
{
$sum = '0';
foreach ($piggyBank->accounts as $current) {
if(null !== $account && $account->id !== $current->id) {
if (null !== $account && $account->id !== $current->id) {
continue;
}
$amount = (string) $current->pivot->current_amount;
@ -137,6 +137,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
throw new FireflyException('[b] Piggy bank repetitions are EOL.');
}
Log::warning('Piggy bank repetitions are EOL.');
return $piggyBank->piggyBankRepetitions()->first();
}
@ -155,15 +156,15 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
throw new FireflyException('[c] Piggy bank repetitions are EOL.');
app('log')->debug(sprintf('Now in getExactAmount(%d, %d, %d)', $piggyBank->id, $repetition->id, $journal->id));
$operator = null;
$currency = null;
$operator = null;
$currency = null;
/** @var JournalRepositoryInterface $journalRepost */
$journalRepost = app(JournalRepositoryInterface::class);
$journalRepost = app(JournalRepositoryInterface::class);
$journalRepost->setUser($this->user);
/** @var AccountRepositoryInterface $accountRepos */
$accountRepos = app(AccountRepositoryInterface::class);
$accountRepos = app(AccountRepositoryInterface::class);
$accountRepos->setUser($this->user);
$defaultCurrency = app('amount')->getDefaultCurrencyByUserGroup($this->user->userGroup);
@ -172,10 +173,10 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
app('log')->debug(sprintf('Piggy bank #%d currency is %s', $piggyBank->id, $piggyBankCurrency->code));
/** @var Transaction $source */
$source = $journal->transactions()->with(['account'])->where('amount', '<', 0)->first();
$source = $journal->transactions()->with(['account'])->where('amount', '<', 0)->first();
/** @var Transaction $destination */
$destination = $journal->transactions()->with(['account'])->where('amount', '>', 0)->first();
$destination = $journal->transactions()->with(['account'])->where('amount', '>', 0)->first();
// matches source, which means amount will be removed from piggy:
if ($source->account_id === $piggyBank->account_id) {
@ -197,7 +198,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
}
// currency of the account + the piggy bank currency are almost the same.
// which amount from the transaction matches?
$amount = null;
$amount = null;
if ((int) $source->transaction_currency_id === $currency->id) {
app('log')->debug('Use normal amount');
$amount = app('steam')->{$operator}($source->amount); // @phpstan-ignore-line
@ -213,8 +214,8 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
}
app('log')->debug(sprintf('The currency is %s and the amount is %s', $currency->code, $amount));
$room = bcsub($piggyBank->target_amount, $repetition->current_amount);
$compare = bcmul($repetition->current_amount, '-1');
$room = bcsub($piggyBank->target_amount, $repetition->current_amount);
$compare = bcmul($repetition->current_amount, '-1');
if (0 === bccomp($piggyBank->target_amount, '0')) {
// amount is zero? then the "room" is positive amount of we wish to add or remove.
@ -246,7 +247,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
return (string) $amount;
}
public function setUser(null | Authenticatable | User $user): void
public function setUser(null|Authenticatable|User $user): void
{
if ($user instanceof User) {
$this->user = $user;
@ -271,12 +272,12 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
{
$currency = app('amount')->getDefaultCurrency();
$set = $this->getPiggyBanks();
$set = $this->getPiggyBanks();
/** @var PiggyBank $piggy */
foreach ($set as $piggy) {
$currentAmount = $this->getRepetition($piggy)->current_amount ?? '0';
$piggy->name = $piggy->name . ' (' . app('amount')->formatAnything($currency, $currentAmount, false) . ')';
$piggy->name = $piggy->name.' ('.app('amount')->formatAnything($currency, $currentAmount, false).')';
}
return $set;
@ -285,14 +286,15 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
public function getPiggyBanks(): Collection
{
return PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', auth()->user()->id)
->with(
[
'objectGroups',
]
)
->orderBy('piggy_banks.order', 'ASC')->distinct()->get(['piggy_banks.*']);
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', auth()->user()->id)
->with(
[
'objectGroups',
]
)
->orderBy('piggy_banks.order', 'ASC')->distinct()->get(['piggy_banks.*'])
;
}
/**
@ -336,11 +338,12 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
/** @var PiggyBank $current */
foreach ($piggies as $current) {
$amount = $this->getCurrentAmount($current, $account);
$amount = $this->getCurrentAmount($current, $account);
$balance = bcsub($balance, $amount);
Log::debug(sprintf('Piggy bank: #%d with amount %s, balance is now %s', $current->id, $amount, $balance));
}
Log::debug(sprintf('Final balance is: %s', $balance));
return $balance;
}
@ -351,7 +354,8 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
$search->whereLike('piggy_banks.name', sprintf('%%%s%%', $query));
}
$search->orderBy('piggy_banks.order', 'ASC')
->orderBy('piggy_banks.name', 'ASC');
->orderBy('piggy_banks.name', 'ASC')
;
return $search->take($limit)->get();
}

View File

@ -111,9 +111,10 @@ interface PiggyBankRepositoryInterface
/**
* Get for piggy account what is left to put in piggies.
*/
public function leftOnAccount(PiggyBank $piggyBank,Account $account, Carbon $date): string;
public function leftOnAccount(PiggyBank $piggyBank, Account $account, Carbon $date): string;
public function removeAmount(PiggyBank $piggyBank, Account $account, string $amount, ?TransactionJournal $journal = null): bool;
public function removeAmountFromAll(PiggyBank $piggyBank, string $amount): void;
public function removeObjectGroup(PiggyBank $piggyBank): PiggyBank;

View File

@ -105,6 +105,7 @@ class Preferences
return $this->getForUser($user, $name, $default);
}
public function getEncryptedForUser(User $user, string $name, null|array|bool|int|string $default = null): ?Preference
{
$result = $this->getForUser($user, $name, $default);

View File

@ -45,39 +45,41 @@ class Steam
public function balanceIgnoreVirtual(Account $account, Carbon $date): string
{
throw new FireflyException('Deprecated method balanceIgnoreVirtual.');
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$repository = app(AccountRepositoryInterface::class);
$repository->setUser($account->user);
$currencyId = (int) $repository->getMetaValue($account, 'currency_id');
$transactions = $account->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.transaction_currency_id', $currencyId)
->get(['transactions.amount'])->toArray();
$nativeBalance = $this->sumTransactions($transactions, 'amount');
$currencyId = (int) $repository->getMetaValue($account, 'currency_id');
$transactions = $account->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.transaction_currency_id', $currencyId)
->get(['transactions.amount'])->toArray()
;
$nativeBalance = $this->sumTransactions($transactions, 'amount');
// get all balances in foreign currency:
$transactions = $account->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.foreign_currency_id', $currencyId)
->where('transactions.transaction_currency_id', '!=', $currencyId)
->get(['transactions.foreign_amount'])->toArray();
$transactions = $account->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.foreign_currency_id', $currencyId)
->where('transactions.transaction_currency_id', '!=', $currencyId)
->get(['transactions.foreign_amount'])->toArray()
;
$foreignBalance = $this->sumTransactions($transactions, 'foreign_amount');
return bcadd($nativeBalance, $foreignBalance);
}
public function balanceConvertedIgnoreVirtual(Account $account, Carbon $date, TransactionCurrency $currency): string
{
$balance = $this->balanceConverted($account, $date, $currency);
$virtual = null === $account->virtual_balance ? '0' : $account->virtual_balance;
$balance = $this->balanceConverted($account, $date, $currency);
$virtual = null === $account->virtual_balance ? '0' : $account->virtual_balance;
// currency of account
$repository = app(AccountRepositoryInterface::class);
$repository = app(AccountRepositoryInterface::class);
$repository->setUser($account->user);
$accountCurrency = $repository->getAccountCurrency($account) ?? app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup);
if ($accountCurrency->id !== $currency->id && 0 !== bccomp($virtual, '0')) {
@ -114,7 +116,7 @@ class Steam
public function balanceInRange(Account $account, Carbon $start, Carbon $end, ?TransactionCurrency $currency = null): array
{
// Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
$cache = new CacheProperties();
$cache = new CacheProperties();
$cache->addProperty($account->id);
$cache->addProperty('balance-in-range');
$cache->addProperty(null !== $currency ? $currency->id : 0);
@ -126,41 +128,42 @@ class Steam
$start->subDay();
$end->addDay();
$balances = [];
$formatted = $start->format('Y-m-d');
$startBalance = $this->balance($account, $start, $currency);
$balances = [];
$formatted = $start->format('Y-m-d');
$startBalance = $this->balance($account, $start, $currency);
$balances[$formatted] = $startBalance;
if (null === $currency) {
$repository = app(AccountRepositoryInterface::class);
$repository->setUser($account->user);
$currency = $repository->getAccountCurrency($account) ?? app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup);
$currency = $repository->getAccountCurrency($account) ?? app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup);
}
$currencyId = $currency->id;
$currencyId = $currency->id;
$start->addDay();
// query!
$set = $account->transactions()
->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d 23:59:59'))
->groupBy('transaction_journals.date')
->groupBy('transactions.transaction_currency_id')
->groupBy('transactions.foreign_currency_id')
->orderBy('transaction_journals.date', 'ASC')
->whereNull('transaction_journals.deleted_at')
->get(
[ // @phpstan-ignore-line
'transaction_journals.date',
'transactions.transaction_currency_id',
\DB::raw('SUM(transactions.amount) AS modified'),
'transactions.foreign_currency_id',
\DB::raw('SUM(transactions.foreign_amount) AS modified_foreign'),
]
);
$set = $account->transactions()
->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d 23:59:59'))
->groupBy('transaction_journals.date')
->groupBy('transactions.transaction_currency_id')
->groupBy('transactions.foreign_currency_id')
->orderBy('transaction_journals.date', 'ASC')
->whereNull('transaction_journals.deleted_at')
->get(
[ // @phpstan-ignore-line
'transaction_journals.date',
'transactions.transaction_currency_id',
\DB::raw('SUM(transactions.amount) AS modified'),
'transactions.foreign_currency_id',
\DB::raw('SUM(transactions.foreign_amount) AS modified_foreign'),
]
)
;
$currentBalance = $startBalance;
$currentBalance = $startBalance;
/** @var Transaction $entry */
foreach ($set as $entry) {
@ -190,7 +193,7 @@ class Steam
public function balanceByTransactions(Account $account, Carbon $date, ?TransactionCurrency $currency): array
{
$cache = new CacheProperties();
$cache = new CacheProperties();
$cache->addProperty($account->id);
$cache->addProperty('balance-by-transactions');
$cache->addProperty($date);
@ -199,12 +202,13 @@ class Steam
return $cache->get();
}
$query = $account->transactions()
->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->orderBy('transaction_journals.date', 'desc')
->orderBy('transaction_journals.order', 'asc')
->orderBy('transaction_journals.description', 'desc')
->orderBy('transactions.amount', 'desc');
$query = $account->transactions()
->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->orderBy('transaction_journals.date', 'desc')
->orderBy('transaction_journals.order', 'asc')
->orderBy('transaction_journals.description', 'desc')
->orderBy('transactions.amount', 'desc')
;
if (null !== $currency) {
$query->where('transactions.transaction_currency_id', $currency->id);
$query->limit(1);
@ -219,7 +223,7 @@ class Steam
$return = [];
$result = $query->get(['transactions.transaction_currency_id', 'transactions.balance_after']);
foreach ($result as $entry) {
$key = (int) $entry->transaction_currency_id;
$key = (int) $entry->transaction_currency_id;
if (array_key_exists($key, $return)) {
continue;
}
@ -238,7 +242,7 @@ class Steam
{
// Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
// abuse chart properties:
$cache = new CacheProperties();
$cache = new CacheProperties();
$cache->addProperty($account->id);
$cache->addProperty('balance');
$cache->addProperty($date);
@ -248,24 +252,26 @@ class Steam
}
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$repository = app(AccountRepositoryInterface::class);
if (null === $currency) {
$currency = $repository->getAccountCurrency($account) ?? app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup);
}
// first part: get all balances in own currency:
$transactions = $account->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.transaction_currency_id', $currency->id)
->get(['transactions.amount'])->toArray();
$nativeBalance = $this->sumTransactions($transactions, 'amount');
$transactions = $account->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.transaction_currency_id', $currency->id)
->get(['transactions.amount'])->toArray()
;
$nativeBalance = $this->sumTransactions($transactions, 'amount');
// get all balances in foreign currency:
$transactions = $account->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.foreign_currency_id', $currency->id)
->where('transactions.transaction_currency_id', '!=', $currency->id)
->get(['transactions.foreign_amount'])->toArray();
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.foreign_currency_id', $currency->id)
->where('transactions.transaction_currency_id', '!=', $currency->id)
->get(['transactions.foreign_amount'])->toArray()
;
$foreignBalance = $this->sumTransactions($transactions, 'foreign_amount');
$balance = bcadd($nativeBalance, $foreignBalance);
$virtual = null === $account->virtual_balance ? '0' : $account->virtual_balance;
@ -284,7 +290,7 @@ class Steam
public function balanceInRangeConverted(Account $account, Carbon $start, Carbon $end, TransactionCurrency $native): array
{
// Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
$cache = new CacheProperties();
$cache = new CacheProperties();
$cache->addProperty($account->id);
$cache->addProperty('balance-in-range-converted');
$cache->addProperty($native->id);
@ -304,34 +310,35 @@ class Steam
Log::debug(sprintf('Start balance on %s is %s', $formatted, $startBalance));
Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__));
$converter = new ExchangeRateConverter();
$converter = new ExchangeRateConverter();
// not sure why this is happening:
$start->addDay();
// grab all transactions between start and end:
$set = $account->transactions()
->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d 23:59:59'))
->orderBy('transaction_journals.date', 'ASC')
->whereNull('transaction_journals.deleted_at')
->get(
[
'transaction_journals.date',
'transactions.transaction_currency_id',
'transactions.amount',
'transactions.foreign_currency_id',
'transactions.foreign_amount',
]
)->toArray();
$set = $account->transactions()
->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d 23:59:59'))
->orderBy('transaction_journals.date', 'ASC')
->whereNull('transaction_journals.deleted_at')
->get(
[
'transaction_journals.date',
'transactions.transaction_currency_id',
'transactions.amount',
'transactions.foreign_currency_id',
'transactions.foreign_amount',
]
)->toArray()
;
// loop the set and convert if necessary:
$currentBalance = $startBalance;
$currentBalance = $startBalance;
/** @var Transaction $transaction */
foreach ($set as $transaction) {
$day = false;
$day = false;
try {
$day = Carbon::parse($transaction['date'], config('app.timezone'));
@ -341,7 +348,7 @@ class Steam
if (false === $day) {
$day = today(config('app.timezone'));
}
$format = $day->format('Y-m-d');
$format = $day->format('Y-m-d');
// if the transaction is in the expected currency, change nothing.
if ((int) $transaction['transaction_currency_id'] === $native->id) {
// change the current balance, set it to today, continue the loop.
@ -364,21 +371,21 @@ class Steam
$currency = $currencies[$currencyId] ?? TransactionCurrency::find($currencyId);
$currencies[$currencyId] = $currency;
$rate = $converter->getCurrencyRate($currency, $native, $day);
$convertedAmount = bcmul($transaction['amount'], $rate);
$currentBalance = bcadd($currentBalance, $convertedAmount);
$balances[$format] = $currentBalance;
$rate = $converter->getCurrencyRate($currency, $native, $day);
$convertedAmount = bcmul($transaction['amount'], $rate);
$currentBalance = bcadd($currentBalance, $convertedAmount);
$balances[$format] = $currentBalance;
Log::debug(sprintf(
'%s: transaction in %s(!). Conversion rate is %s. %s %s = %s %s',
$format,
$currency->code,
$rate,
$currency->code,
$transaction['amount'],
$native->code,
$convertedAmount
));
'%s: transaction in %s(!). Conversion rate is %s. %s %s = %s %s',
$format,
$currency->code,
$rate,
$currency->code,
$transaction['amount'],
$native->code,
$convertedAmount
));
}
$cache->store($balances);
@ -410,7 +417,7 @@ class Steam
{
// Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
Log::debug(sprintf('Now in balanceConverted (%s) for account #%d, converting to %s', $date->format('Y-m-d'), $account->id, $native->code));
$cache = new CacheProperties();
$cache = new CacheProperties();
$cache->addProperty($account->id);
$cache->addProperty('balance');
$cache->addProperty($date);
@ -431,66 +438,72 @@ class Steam
return $this->balance($account, $date);
}
$new = [];
$existing = [];
$new[] = $account->transactions() // 1
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.transaction_currency_id', $currency->id)
->whereNull('transactions.foreign_currency_id')
->get(['transaction_journals.date', 'transactions.amount'])->toArray();
$new = [];
$existing = [];
$new[] = $account->transactions() // 1
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.transaction_currency_id', $currency->id)
->whereNull('transactions.foreign_currency_id')
->get(['transaction_journals.date', 'transactions.amount'])->toArray()
;
Log::debug(sprintf('%d transaction(s) in set #1', count($new[0])));
$existing[] = $account->transactions() // 2
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.transaction_currency_id', $native->id)
->whereNull('transactions.foreign_currency_id')
->get(['transactions.amount'])->toArray();
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.transaction_currency_id', $native->id)
->whereNull('transactions.foreign_currency_id')
->get(['transactions.amount'])->toArray()
;
Log::debug(sprintf('%d transaction(s) in set #2', count($existing[0])));
$new[] = $account->transactions() // 3
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.transaction_currency_id', '!=', $currency->id)
->where('transactions.transaction_currency_id', '!=', $native->id)
->whereNull('transactions.foreign_currency_id')
->get(['transaction_journals.date', 'transactions.amount'])->toArray();
$new[] = $account->transactions() // 3
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.transaction_currency_id', '!=', $currency->id)
->where('transactions.transaction_currency_id', '!=', $native->id)
->whereNull('transactions.foreign_currency_id')
->get(['transaction_journals.date', 'transactions.amount'])->toArray()
;
Log::debug(sprintf('%d transactions in set #3', count($new[1])));
$existing[] = $account->transactions() // 4
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.foreign_currency_id', $native->id)
->whereNotNull('transactions.foreign_amount')
->get(['transactions.foreign_amount'])->toArray();
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.foreign_currency_id', $native->id)
->whereNotNull('transactions.foreign_amount')
->get(['transactions.foreign_amount'])->toArray()
;
Log::debug(sprintf('%d transactions in set #4', count($existing[1])));
$new[] = $account->transactions()// 5
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.transaction_currency_id', $currency->id)
->where('transactions.foreign_currency_id', '!=', $native->id)
->whereNotNull('transactions.foreign_amount')
->get(['transaction_journals.date', 'transactions.amount'])->toArray();
$new[] = $account->transactions()// 5
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.transaction_currency_id', $currency->id)
->where('transactions.foreign_currency_id', '!=', $native->id)
->whereNotNull('transactions.foreign_amount')
->get(['transaction_journals.date', 'transactions.amount'])->toArray()
;
Log::debug(sprintf('%d transactions in set #5', count($new[2])));
$new[] = $account->transactions()// 6
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.transaction_currency_id', '!=', $currency->id)
->where('transactions.foreign_currency_id', '!=', $native->id)
->whereNotNull('transactions.foreign_amount')
->get(['transaction_journals.date', 'transactions.amount'])->toArray();
$new[] = $account->transactions()// 6
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->where('transactions.transaction_currency_id', '!=', $currency->id)
->where('transactions.foreign_currency_id', '!=', $native->id)
->whereNotNull('transactions.foreign_amount')
->get(['transaction_journals.date', 'transactions.amount'])->toArray()
;
Log::debug(sprintf('%d transactions in set #6', count($new[3])));
// process both sets of transactions. Of course, no need to convert set "existing".
$balance = $this->sumTransactions($existing[0], 'amount');
$balance = bcadd($balance, $this->sumTransactions($existing[1], 'foreign_amount'));
$balance = $this->sumTransactions($existing[0], 'amount');
$balance = bcadd($balance, $this->sumTransactions($existing[1], 'foreign_amount'));
Log::debug(sprintf('Balance from set #2 and #4 is %f', $balance));
// need to convert the others. All sets use the "amount" value as their base (that's easy)
// but we need to convert each transaction separately because the date difference may
// incur huge currency changes.
Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__));
$start = clone $date;
$end = clone $date;
$converter = new ExchangeRateConverter();
$start = clone $date;
$end = clone $date;
$converter = new ExchangeRateConverter();
foreach ($new as $set) {
foreach ($set as $transaction) {
$currentDate = false;
@ -513,7 +526,7 @@ class Steam
foreach ($new as $set) {
foreach ($set as $transaction) {
$currentDate = false;
$currentDate = false;
try {
$currentDate = Carbon::parse($transaction['date'], config('app.timezone'));
@ -530,9 +543,9 @@ class Steam
}
// add virtual balance (also needs conversion)
$virtual = null === $account->virtual_balance ? '0' : $account->virtual_balance;
$virtual = $converter->convert($currency, $native, $account->created_at, $virtual);
$balance = bcadd($balance, $virtual);
$virtual = null === $account->virtual_balance ? '0' : $account->virtual_balance;
$virtual = $converter->convert($currency, $native, $account->created_at, $virtual);
$balance = bcadd($balance, $virtual);
$converter->summarize();
$cache->store($balance);
@ -549,9 +562,9 @@ class Steam
public function balancesByAccounts(Collection $accounts, Carbon $date): array
{
// Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
$ids = $accounts->pluck('id')->toArray();
$ids = $accounts->pluck('id')->toArray();
// cache this property.
$cache = new CacheProperties();
$cache = new CacheProperties();
$cache->addProperty($ids);
$cache->addProperty('balances');
$cache->addProperty($date);
@ -580,9 +593,9 @@ class Steam
public function balancesByAccountsConverted(Collection $accounts, Carbon $date): array
{
// Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
$ids = $accounts->pluck('id')->toArray();
$ids = $accounts->pluck('id')->toArray();
// cache this property.
$cache = new CacheProperties();
$cache = new CacheProperties();
$cache->addProperty($ids);
$cache->addProperty('balances-converted');
$cache->addProperty($date);
@ -598,9 +611,9 @@ class Steam
$default = app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup);
$result[$account->id]
= [
'balance' => $this->balance($account, $date),
'native_balance' => $this->balanceConverted($account, $date, $default),
];
'balance' => $this->balance($account, $date),
'native_balance' => $this->balanceConverted($account, $date, $default),
];
}
$cache->store($result);
@ -614,9 +627,9 @@ class Steam
public function balancesPerCurrencyByAccounts(Collection $accounts, Carbon $date): array
{
// Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
$ids = $accounts->pluck('id')->toArray();
$ids = $accounts->pluck('id')->toArray();
// cache this property.
$cache = new CacheProperties();
$cache = new CacheProperties();
$cache->addProperty($ids);
$cache->addProperty('balances-per-currency');
$cache->addProperty($date);
@ -641,7 +654,7 @@ class Steam
{
// Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
// abuse chart properties:
$cache = new CacheProperties();
$cache = new CacheProperties();
$cache->addProperty($account->id);
$cache->addProperty('balance-per-currency');
$cache->addProperty($date);
@ -649,9 +662,10 @@ class Steam
return $cache->get();
}
$query = $account->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->groupBy('transactions.transaction_currency_id');
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
->groupBy('transactions.transaction_currency_id')
;
$balances = $query->get(['transactions.transaction_currency_id', \DB::raw('SUM(transactions.amount) as sum_for_currency')]); // @phpstan-ignore-line
$return = [];
@ -683,10 +697,10 @@ class Steam
// Log::debug(sprintf('Trying bcround("%s",%d)', $number, $precision));
if (str_contains($number, '.')) {
if ('-' !== $number[0]) {
return bcadd($number, '0.' . str_repeat('0', $precision) . '5', $precision);
return bcadd($number, '0.'.str_repeat('0', $precision).'5', $precision);
}
return bcsub($number, '0.' . str_repeat('0', $precision) . '5', $precision);
return bcsub($number, '0.'.str_repeat('0', $precision).'5', $precision);
}
return $number;
@ -769,15 +783,15 @@ class Steam
{
$list = [];
$set = auth()->user()->transactions()
->whereIn('transactions.account_id', $accounts)
->groupBy(['transactions.account_id', 'transaction_journals.user_id'])
->get(['transactions.account_id', \DB::raw('MAX(transaction_journals.date) AS max_date')]) // @phpstan-ignore-line
$set = auth()->user()->transactions()
->whereIn('transactions.account_id', $accounts)
->groupBy(['transactions.account_id', 'transaction_journals.user_id'])
->get(['transactions.account_id', \DB::raw('MAX(transaction_journals.date) AS max_date')]) // @phpstan-ignore-line
;
/** @var Transaction $entry */
foreach ($set as $entry) {
$date = new Carbon($entry->max_date, config('app.timezone'));
$date = new Carbon($entry->max_date, config('app.timezone'));
$date->setTimezone(config('app.timezone'));
$list[$entry->account_id] = $date;
}
@ -852,9 +866,9 @@ class Steam
public function getSafeUrl(string $unknownUrl, string $safeUrl): string
{
// Log::debug(sprintf('getSafeUrl(%s, %s)', $unknownUrl, $safeUrl));
$returnUrl = $safeUrl;
$unknownHost = parse_url($unknownUrl, PHP_URL_HOST);
$safeHost = parse_url($safeUrl, PHP_URL_HOST);
$returnUrl = $safeUrl;
$unknownHost = parse_url($unknownUrl, PHP_URL_HOST);
$safeHost = parse_url($safeUrl, PHP_URL_HOST);
if (null !== $unknownHost && $unknownHost === $safeHost) {
$returnUrl = $unknownUrl;
@ -891,7 +905,7 @@ class Steam
*/
public function floatalize(string $value): string
{
$value = strtoupper($value);
$value = strtoupper($value);
if (!str_contains($value, 'E')) {
return $value;
}

View File

@ -82,6 +82,7 @@ class UpdatePiggybank implements ActionInterface
if ($source->account_id === $piggyBank->account_id) {
app('log')->debug('Piggy bank account is linked to source, so remove amount from piggy bank.');
throw new FireflyException('Reference the correct account here.');
$this->removeAmount($piggyBank, $journal, $journalObj, $destination->amount);

View File

@ -78,7 +78,7 @@ class PiggyBankTransformer extends AbstractTransformer
// get currently saved amount:
$currency = $piggyBank->transactionCurrency;
$currentAmount = $this->piggyRepos->getCurrentAmount($piggyBank);
$currentAmount = $this->piggyRepos->getCurrentAmount($piggyBank);
// Amounts, depending on 0.0 state of target amount
$percentage = null;

View File

@ -36,7 +36,6 @@ use FireflyIII\Models\Category;
use FireflyIII\Models\CurrencyExchangeRate;
use FireflyIII\Models\GroupMembership;
use FireflyIII\Models\ObjectGroup;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Preference;
use FireflyIII\Models\Recurrence;
use FireflyIII\Models\Role;
@ -107,7 +106,8 @@ class User extends Authenticatable
return $this->hasMany(Account::class);
}
public function piggyBanks() {
public function piggyBanks(): void
{
throw new FireflyException('Method no longer supported.');
}
@ -263,38 +263,38 @@ class User extends Authenticatable
app('log')->debug(sprintf('in hasAnyRoleInGroup(%s)', implode(', ', $roles)));
/** @var Collection $dbRoles */
$dbRoles = UserRole::whereIn('title', $roles)->get();
$dbRoles = UserRole::whereIn('title', $roles)->get();
if (0 === $dbRoles->count()) {
app('log')->error(sprintf('Could not find role(s): %s. Probably migration mishap.', implode(', ', $roles)));
return false;
}
$dbRolesIds = $dbRoles->pluck('id')->toArray();
$dbRolesTitles = $dbRoles->pluck('title')->toArray();
$dbRolesIds = $dbRoles->pluck('id')->toArray();
$dbRolesTitles = $dbRoles->pluck('title')->toArray();
/** @var Collection $groupMemberships */
$groupMemberships = $this->groupMemberships()->whereIn('user_role_id', $dbRolesIds)->where('user_group_id', $userGroup->id)->get();
if (0 === $groupMemberships->count()) {
app('log')->error(sprintf(
'User #%d "%s" does not have roles %s in user group #%d "%s"',
$this->id,
$this->email,
implode(', ', $roles),
$userGroup->id,
$userGroup->title
));
'User #%d "%s" does not have roles %s in user group #%d "%s"',
$this->id,
$this->email,
implode(', ', $roles),
$userGroup->id,
$userGroup->title
));
return false;
}
foreach ($groupMemberships as $membership) {
app('log')->debug(sprintf(
'User #%d "%s" has role "%s" in user group #%d "%s"',
$this->id,
$this->email,
$membership->userRole->title,
$userGroup->id,
$userGroup->title
));
'User #%d "%s" has role "%s" in user group #%d "%s"',
$this->id,
$this->email,
$membership->userRole->title,
$userGroup->id,
$userGroup->title
));
if (in_array($membership->userRole->title, $dbRolesTitles, true)) {
app('log')->debug(sprintf('Return true, found role "%s"', $membership->userRole->title));
@ -302,13 +302,13 @@ class User extends Authenticatable
}
}
app('log')->error(sprintf(
'User #%d "%s" does not have roles %s in user group #%d "%s"',
$this->id,
$this->email,
implode(', ', $roles),
$userGroup->id,
$userGroup->title
));
'User #%d "%s" does not have roles %s in user group #%d "%s"',
$this->id,
$this->email,
implode(', ', $roles),
$userGroup->id,
$userGroup->title
));
return false;
}
@ -360,13 +360,13 @@ class User extends Authenticatable
*/
public function routeNotificationFor($driver, $notification = null)
{
$method = 'routeNotificationFor' . Str::studly($driver);
$method = 'routeNotificationFor'.Str::studly($driver);
if (method_exists($this, $method)) {
return $this->{$method}($notification); // @phpstan-ignore-line
}
$email = $this->email;
$email = $this->email;
// see if user has alternative email address:
$pref = app('preferences')->getForUser($this, 'remote_guard_alt_email');
$pref = app('preferences')->getForUser($this, 'remote_guard_alt_email');
if (null !== $pref) {
$email = $pref->data;
}
@ -411,11 +411,11 @@ class User extends Authenticatable
public function routeNotificationForSlack(Notification $notification): ?string
{
// this check does not validate if the user is owner, Should be done by notification itself.
$res = app('fireflyconfig')->getEncrypted('slack_webhook_url', '')->data;
$res = app('fireflyconfig')->getEncrypted('slack_webhook_url', '')->data;
if (is_array($res)) {
$res = '';
}
$res = (string) $res;
$res = (string) $res;
if (property_exists($notification, 'type') && 'owner' === $notification->type) {
return $res;

View File

@ -110,7 +110,7 @@ return [
'running_balance_column' => env('USE_RUNNING_BALANCE', false),
// see cer.php for exchange rates feature flag.
],
'version' => 'develop/2024-11-25',
'version' => 'branch-v6.2',
'api_version' => '2.1.0', // field is no longer used.
'db_version' => 25,

View File

@ -28,8 +28,8 @@ return [
'slack' => ['enabled' => true, 'ui_configurable' => 1],
'ntfy' => ['enabled' => true, 'ui_configurable' => 1],
'pushover' => ['enabled' => true, 'ui_configurable' => 1],
// 'gotify' => ['enabled' => false, 'ui_configurable' => 0],
// 'pushbullet' => ['enabled' => false, 'ui_configurable' => 0],
// 'gotify' => ['enabled' => false, 'ui_configurable' => 0],
// 'pushbullet' => ['enabled' => false, 'ui_configurable' => 0],
],
'notifications' => [
'user' => [

761
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -5,8 +5,8 @@
"flash_warning": "\u00a1Advertencia!",
"flash_success": "\u00a1Operaci\u00f3n correcta!",
"close": "Cerrar",
"select_dest_account": "Please select or type a valid destination account name",
"select_source_account": "Please select or type a valid source account name",
"select_dest_account": "Por favor, seleccione o escriba un nombre de cuenta de destino v\u00e1lido",
"select_source_account": "Por favor, seleccione o escriba un nombre de cuenta de origen v\u00e1lido",
"split_transaction_title": "Descripci\u00f3n de la transacci\u00f3n dividida",
"errors_submission": "Hubo un problema con su env\u00edo. Por favor, compruebe los siguientes errores.",
"split": "Separar",

View File

@ -109,7 +109,7 @@ return [
// reset password
'reset_pw_subject' => 'Your password reset request',
'reset_pw_message' => 'You have received password reset instructions in your email. If this was you, please follow the instructions.',
'reset_pw_message' => 'You have received password reset instructions in your email. If this was you, please follow the instructions.',
'reset_pw_instructions' => 'Somebody tried to reset your password. If it was you, please follow the link below to do so.',
'reset_pw_warning' => '**PLEASE** verify that the link actually goes to the Firefly III you expect it to go!',

View File

@ -1290,7 +1290,7 @@ return [
'create_recurring_from_transaction' => 'Create recurring transaction based on transaction',
// preferences
'test_notifications_buttons' => 'To test your configuration, use the buttons below. Please note that the buttons have no spam control.',
'test_notifications_buttons' => 'To test your configuration, use the buttons below. Please note that the buttons have no spam control.',
'dark_mode_option_browser' => 'Let your browser decide',
'dark_mode_option_light' => 'Always light',
'dark_mode_option_dark' => 'Always dark',