Code cleanup that (hopefully) matches style CI

This commit is contained in:
James Cole
2020-03-17 14:54:25 +01:00
parent e02e747f1b
commit b0c9fc0792
35 changed files with 980 additions and 959 deletions

View File

@@ -30,6 +30,7 @@ use Schema;
/** /**
* Class CorrectDatabase * Class CorrectDatabase
*
* @codeCoverageIgnore * @codeCoverageIgnore
*/ */
class CorrectDatabase extends Command class CorrectDatabase extends Command
@@ -73,7 +74,7 @@ class CorrectDatabase extends Command
'firefly-iii:fix-ob-currencies', 'firefly-iii:fix-ob-currencies',
'firefly-iii:fix-long-descriptions', 'firefly-iii:fix-long-descriptions',
'firefly-iii:fix-recurring-transactions', 'firefly-iii:fix-recurring-transactions',
'firefly-iii:restore-oauth-keys' 'firefly-iii:restore-oauth-keys',
]; ];
foreach ($commands as $command) { foreach ($commands as $command) {
$this->line(sprintf('Now executing %s', $command)); $this->line(sprintf('Now executing %s', $command));

View File

@@ -50,8 +50,8 @@ class CreateAccessTokens extends Command
/** /**
* Execute the console command. * Execute the console command.
* *
* @return int
* @throws Exception * @throws Exception
* @return int
*/ */
public function handle(): int public function handle(): int
{ {

View File

@@ -49,15 +49,15 @@ class DeleteEmptyGroups extends Command
/** /**
* Execute the console command. * Execute the console command.
* *
* @return mixed
* @throws Exception; * @throws Exception;
* @return mixed
*/ */
public function handle(): int public function handle(): int
{ {
Log::debug(sprintf('Now in %s', __METHOD__)); Log::debug(sprintf('Now in %s', __METHOD__));
$start = microtime(true); $start = microtime(true);
$groupIds = $groupIds
TransactionGroup = TransactionGroup
::leftJoin('transaction_journals', 'transaction_groups.id', '=', 'transaction_journals.transaction_group_id') ::leftJoin('transaction_journals', 'transaction_groups.id', '=', 'transaction_journals.transaction_group_id')
->whereNull('transaction_journals.id')->get(['transaction_groups.id'])->pluck('id')->toArray(); ->whereNull('transaction_journals.id')->get(['transaction_groups.id'])->pluck('id')->toArray();

View File

@@ -51,8 +51,8 @@ class DeleteOrphanedTransactions extends Command
/** /**
* Execute the console command. * Execute the console command.
* *
* @return int
* @throws Exception * @throws Exception
* @return int
*/ */
public function handle(): int public function handle(): int
{ {

View File

@@ -49,6 +49,7 @@ class DeleteZeroAmount extends Command
/** /**
* Execute the console command. * Execute the console command.
*
* @return int * @return int
*/ */
public function handle(): int public function handle(): int

View File

@@ -49,20 +49,20 @@ class FixAccountTypes extends Command
* @var string * @var string
*/ */
protected $signature = 'firefly-iii:fix-account-types'; protected $signature = 'firefly-iii:fix-account-types';
/** @var int */
private $count;
/** @var array */ /** @var array */
private $expected; private $expected;
/** @var AccountFactory */ /** @var AccountFactory */
private $factory; private $factory;
/** @var array */ /** @var array */
private $fixable; private $fixable;
/** @var int */
private $count;
/** /**
* Execute the console command. * Execute the console command.
* *
* @return int
* @throws FireflyException * @throws FireflyException
* @return int
*/ */
public function handle(): int public function handle(): int
{ {
@@ -109,23 +109,12 @@ class FixAccountTypes extends Command
return 0; return 0;
} }
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
* @codeCoverageIgnore
*/
private function stupidLaravel(): void
{
$this->count = 0;
}
/** /**
* @param TransactionJournal $journal * @param TransactionJournal $journal
* @param string $type * @param string $type
* @param Transaction $source * @param Transaction $source
* @param Transaction $dest * @param Transaction $dest
*
* @throws FireflyException * @throws FireflyException
*/ */
private function fixJournal(TransactionJournal $journal, string $type, Transaction $source, Transaction $dest): void private function fixJournal(TransactionJournal $journal, string $type, Transaction $source, Transaction $dest): void
@@ -278,4 +267,16 @@ class FixAccountTypes extends Command
$this->fixJournal($journal, $type, $sourceTransaction, $destTransaction); $this->fixJournal($journal, $type, $sourceTransaction, $destTransaction);
} }
} }
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
* @codeCoverageIgnore
*/
private function stupidLaravel(): void
{
$this->count = 0;
}
} }

View File

@@ -73,6 +73,7 @@ class FixLongDescriptions extends Command
} }
$end = round(microtime(true) - $start, 2); $end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified all transaction group and journal title lengths in %s seconds.', $end)); $this->info(sprintf('Verified all transaction group and journal title lengths in %s seconds.', $end));
return 0; return 0;
} }
} }

View File

@@ -54,8 +54,8 @@ class DecryptDatabase extends Command
/** /**
* Execute the console command. * Execute the console command.
* *
* @return int
* @throws FireflyException * @throws FireflyException
* @return int
*/ */
public function handle(): int public function handle(): int
{ {
@@ -142,8 +142,9 @@ class DecryptDatabase extends Command
* Tries to decrypt data. Will only throw an exception when the MAC is invalid. * Tries to decrypt data. Will only throw an exception when the MAC is invalid.
* *
* @param $value * @param $value
* @return string *
* @throws FireflyException * @throws FireflyException
* @return string
*/ */
private function tryDecrypt($value) private function tryDecrypt($value)
{ {

View File

@@ -22,6 +22,7 @@
namespace FireflyIII\Console\Commands\Export; namespace FireflyIII\Console\Commands\Export;
use Carbon\Carbon; use Carbon\Carbon;
use Exception;
use FireflyIII\Console\Commands\VerifiesAccessToken; use FireflyIII\Console\Commands\VerifiesAccessToken;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\AccountType; use FireflyIII\Models\AccountType;
@@ -32,6 +33,7 @@ use FireflyIII\User;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use InvalidArgumentException; use InvalidArgumentException;
use League\Csv\CannotInsertRecord;
use Log; use Log;
/** /**
@@ -79,9 +81,9 @@ class ExportData extends Command
/** /**
* Execute the console command. * Execute the console command.
* *
* @return int
* @throws FireflyException * @throws FireflyException
* @throws \League\Csv\CannotInsertRecord * @throws CannotInsertRecord
* @return int
*/ */
public function handle(): int public function handle(): int
{ {
@@ -162,8 +164,8 @@ class ExportData extends Command
} }
/** /**
* @return Collection
* @throws FireflyException * @throws FireflyException
* @return Collection
*/ */
private function getAccountsParameter(): Collection private function getAccountsParameter(): Collection
{ {
@@ -195,9 +197,9 @@ class ExportData extends Command
/** /**
* @param string $field * @param string $field
* *
* @return Carbon
* @throws FireflyException * @throws FireflyException
* @throws \Exception * @throws Exception
* @return Carbon
*/ */
private function getDateParameter(string $field): Carbon private function getDateParameter(string $field): Carbon
{ {
@@ -231,8 +233,8 @@ class ExportData extends Command
} }
/** /**
* @return string
* @throws FireflyException * @throws FireflyException
* @return string
*/ */
private function getExportDirectory(): string private function getExportDirectory(): string
{ {
@@ -248,8 +250,8 @@ class ExportData extends Command
} }
/** /**
* @return array
* @throws FireflyException * @throws FireflyException
* @return array
*/ */
private function parseOptions(): array private function parseOptions(): array
{ {

View File

@@ -39,6 +39,7 @@ use Log;
/** /**
* Class CreateCSVImport. * Class CreateCSVImport.
*
* @deprecated * @deprecated
* @codeCoverageIgnore * @codeCoverageIgnore
*/ */
@@ -62,12 +63,12 @@ class CreateCSVImport extends Command
{configuration? : The configuration file to use for the import.} {configuration? : The configuration file to use for the import.}
{--user=1 : The user ID that the import should import for.} {--user=1 : The user ID that the import should import for.}
{--token= : The user\'s access token.}'; {--token= : The user\'s access token.}';
/** @var UserRepositoryInterface */
private $userRepository;
/** @var ImportJobRepositoryInterface */
private $importRepository;
/** @var ImportJob */ /** @var ImportJob */
private $importJob; private $importJob;
/** @var ImportJobRepositoryInterface */
private $importRepository;
/** @var UserRepositoryInterface */
private $userRepository;
/** /**
* Run the command. * Run the command.
@@ -148,22 +149,10 @@ class CreateCSVImport extends Command
return 0; return 0;
} }
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
* @codeCoverageIgnore
*/
private function stupidLaravel(): void
{
$this->userRepository = app(UserRepositoryInterface::class);
$this->importRepository = app(ImportJobRepositoryInterface::class);
}
/** /**
* @param string $message * @param string $message
* @param array|null $data * @param array|null $data
*
* @codeCoverageIgnore * @codeCoverageIgnore
*/ */
private function errorLine(string $message, array $data = null): void private function errorLine(string $message, array $data = null): void
@@ -173,9 +162,34 @@ class CreateCSVImport extends Command
} }
/**
*
*/
private function giveFeedback(): void
{
$this->infoLine('Job has finished.');
if (null !== $this->importJob->tag) {
$this->infoLine(sprintf('%d transaction(s) have been imported.', $this->importJob->tag->transactionJournals->count()));
$this->infoLine(sprintf('You can find your transactions under tag "%s"', $this->importJob->tag->tag));
}
if (null === $this->importJob->tag) {
$this->errorLine('No transactions have been imported :(.');
}
if (count($this->importJob->errors) > 0) {
$this->infoLine(sprintf('%d error(s) occurred:', count($this->importJob->errors)));
foreach ($this->importJob->errors as $err) {
$this->errorLine('- ' . $err);
}
}
}
/** /**
* @param string $message * @param string $message
* @param array $data * @param array $data
*
* @codeCoverageIgnore * @codeCoverageIgnore
*/ */
private function infoLine(string $message, array $data = null): void private function infoLine(string $message, array $data = null): void
@@ -184,65 +198,6 @@ class CreateCSVImport extends Command
$this->line($message); $this->line($message);
} }
/**
* Verify user inserts correct arguments.
*
* @noinspection MultipleReturnStatementsInspection
* @return bool
* @codeCoverageIgnore
*/
private function validArguments(): bool
{
$file = (string)$this->argument('file');
$configuration = (string)$this->argument('configuration');
$cwd = getcwd();
$enabled = (bool)config('import.enabled.file');
if (false === $enabled) {
$this->errorLine('CSV Provider is not enabled.');
return false;
}
if (!file_exists($file)) {
$this->errorLine(sprintf('Firefly III cannot find file "%s" (working directory: "%s").', $file, $cwd));
return false;
}
if (!file_exists($configuration)) {
$this->errorLine(sprintf('Firefly III cannot find configuration file "%s" (working directory: "%s").', $configuration, $cwd));
return false;
}
$configurationData = json_decode(file_get_contents($configuration), true, 512, JSON_THROW_ON_ERROR);
if (null === $configurationData) {
$this->errorLine(sprintf('Firefly III cannot read the contents of configuration file "%s" (working directory: "%s").', $configuration, $cwd));
return false;
}
return true;
}
/**
* Store the supplied file as an attachment to this job.
*
* @param string $file
* @throws FireflyException
*/
private function storeFile(string $file): void
{
// store file as attachment.
if ('' !== $file) {
$messages = $this->importRepository->storeCLIUpload($this->importJob, 'import_file', $file);
if ($messages->count() > 0) {
throw new FireflyException($messages->first());
}
}
}
/** /**
* Keep repeating import call until job lands on "provider_finished". * Keep repeating import call until job lands on "provider_finished".
* *
@@ -309,26 +264,75 @@ class CreateCSVImport extends Command
} }
/** /**
* Store the supplied file as an attachment to this job.
* *
* @param string $file
*
* @throws FireflyException
*/ */
private function giveFeedback(): void private function storeFile(string $file): void
{ {
$this->infoLine('Job has finished.'); // store file as attachment.
if ('' !== $file) {
$messages = $this->importRepository->storeCLIUpload($this->importJob, 'import_file', $file);
if (null !== $this->importJob->tag) { if ($messages->count() > 0) {
$this->infoLine(sprintf('%d transaction(s) have been imported.', $this->importJob->tag->transactionJournals->count())); throw new FireflyException($messages->first());
$this->infoLine(sprintf('You can find your transactions under tag "%s"', $this->importJob->tag->tag)); }
}
} }
if (null === $this->importJob->tag) { /**
$this->errorLine('No transactions have been imported :(.'); * Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
} * executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
if (count($this->importJob->errors) > 0) { * be called from the handle method instead of using the constructor to initialize the command.
$this->infoLine(sprintf('%d error(s) occurred:', count($this->importJob->errors))); *
foreach ($this->importJob->errors as $err) { * @codeCoverageIgnore
$this->errorLine('- ' . $err); */
} private function stupidLaravel(): void
{
$this->userRepository = app(UserRepositoryInterface::class);
$this->importRepository = app(ImportJobRepositoryInterface::class);
} }
/**
* Verify user inserts correct arguments.
*
* @noinspection MultipleReturnStatementsInspection
* @return bool
* @codeCoverageIgnore
*/
private function validArguments(): bool
{
$file = (string) $this->argument('file');
$configuration = (string) $this->argument('configuration');
$cwd = getcwd();
$enabled = (bool) config('import.enabled.file');
if (false === $enabled) {
$this->errorLine('CSV Provider is not enabled.');
return false;
}
if (!file_exists($file)) {
$this->errorLine(sprintf('Firefly III cannot find file "%s" (working directory: "%s").', $file, $cwd));
return false;
}
if (!file_exists($configuration)) {
$this->errorLine(sprintf('Firefly III cannot find configuration file "%s" (working directory: "%s").', $configuration, $cwd));
return false;
}
$configurationData = json_decode(file_get_contents($configuration), true, 512, JSON_THROW_ON_ERROR);
if (null === $configurationData) {
$this->errorLine(sprintf('Firefly III cannot read the contents of configuration file "%s" (working directory: "%s").', $configuration, $cwd));
return false;
}
return true;
} }
} }

View File

@@ -30,6 +30,7 @@ use Schema;
/** /**
* Class ReportIntegrity * Class ReportIntegrity
*
* @codeCoverageIgnore * @codeCoverageIgnore
*/ */
class ReportIntegrity extends Command class ReportIntegrity extends Command

View File

@@ -68,35 +68,32 @@ class ApplyRules extends Command
{--all_rules : If set, will overrule both settings and simply apply ALL of your rules.} {--all_rules : If set, will overrule both settings and simply apply ALL of your rules.}
{--start_date= : The date of the earliest transaction to be included (inclusive). If omitted, will be your very first transaction ever. Format: YYYY-MM-DD} {--start_date= : The date of the earliest transaction to be included (inclusive). If omitted, will be your very first transaction ever. Format: YYYY-MM-DD}
{--end_date= : The date of the latest transaction to be included (inclusive). If omitted, will be your latest transaction ever. Format: YYYY-MM-DD}'; {--end_date= : The date of the latest transaction to be included (inclusive). If omitted, will be your latest transaction ever. Format: YYYY-MM-DD}';
/** @var Collection */
private $accounts;
/** @var array */ /** @var array */
private $acceptedAccounts; private $acceptedAccounts;
/** @var Collection */
private $accounts;
/** @var bool */
private $allRules;
/** @var Carbon */ /** @var Carbon */
private $endDate; private $endDate;
/** @var Collection */
private $groups;
/** @var RuleGroupRepositoryInterface */
private $ruleGroupRepository;
/** @var array */ /** @var array */
private $ruleGroupSelection; private $ruleGroupSelection;
/** @var RuleRepositoryInterface */
private $ruleRepository;
/** @var array */ /** @var array */
private $ruleSelection; private $ruleSelection;
/** @var Carbon */ /** @var Carbon */
private $startDate; private $startDate;
/** @var Collection */
private $groups;
/** @var bool */
private $allRules;
/** @var RuleRepositoryInterface */
private $ruleRepository;
/** @var RuleGroupRepositoryInterface */
private $ruleGroupRepository;
/** /**
* Execute the console command. * Execute the console command.
* *
* @return int
* @throws FireflyException * @throws FireflyException
* @return int
*/ */
public function handle(): int public function handle(): int
{ {
@@ -169,6 +166,49 @@ class ApplyRules extends Command
return 0; return 0;
} }
/**
* @return array
*/
private function getRulesToApply(): array
{
$rulesToApply = [];
/** @var RuleGroup $group */
foreach ($this->groups as $group) {
$rules = $this->ruleGroupRepository->getActiveStoreRules($group);
/** @var Rule $rule */
foreach ($rules as $rule) {
// if in rule selection, or group in selection or all rules, it's included.
$test = $this->includeRule($rule, $group);
if (true === $test) {
Log::debug(sprintf('Will include rule #%d "%s"', $rule->id, $rule->title));
$rulesToApply[] = $rule->id;
}
}
}
return $rulesToApply;
}
/**
*/
private function grabAllRules(): void
{
$this->groups = $this->ruleGroupRepository->getActiveGroups();
}
/**
* @param Rule $rule
* @param RuleGroup $group
*
* @return bool
*/
private function includeRule(Rule $rule, RuleGroup $group): bool
{
return in_array($group->id, $this->ruleGroupSelection, true)
|| in_array($rule->id, $this->ruleSelection, true)
|| $this->allRules;
}
/** /**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is * Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should * executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
@@ -189,8 +229,8 @@ class ApplyRules extends Command
} }
/** /**
* @return bool
* @throws FireflyException * @throws FireflyException
* @return bool
*/ */
private function verifyInput(): bool private function verifyInput(): bool
{ {
@@ -212,8 +252,8 @@ class ApplyRules extends Command
} }
/** /**
* @return bool
* @throws FireflyException * @throws FireflyException
* @return bool
*/ */
private function verifyInputAccounts(): bool private function verifyInputAccounts(): bool
{ {
@@ -258,6 +298,42 @@ class ApplyRules extends Command
} }
/**
* @throws FireflyException
*/
private function verifyInputDates(): void
{
// parse start date.
$startDate = Carbon::now()->startOfMonth();
$startString = $this->option('start_date');
if (null === $startString) {
/** @var JournalRepositoryInterface $repository */
$repository = app(JournalRepositoryInterface::class);
$repository->setUser($this->getUser());
$first = $repository->firstNull();
if (null !== $first) {
$startDate = $first->date;
}
}
if (null !== $startString && '' !== $startString) {
$startDate = Carbon::createFromFormat('Y-m-d', $startString);
}
// parse end date
$endDate = Carbon::now();
$endString = $this->option('end_date');
if (null !== $endString && '' !== $endString) {
$endDate = Carbon::createFromFormat('Y-m-d', $endString);
}
if ($startDate > $endDate) {
[$endDate, $startDate] = [$startDate, $endDate];
}
$this->startDate = $startDate;
$this->endDate = $endDate;
}
/** /**
* @return bool * @return bool
*/ */
@@ -317,82 +393,4 @@ class ApplyRules extends Command
return true; return true;
} }
/**
* @throws FireflyException
*/
private function verifyInputDates(): void
{
// parse start date.
$startDate = Carbon::now()->startOfMonth();
$startString = $this->option('start_date');
if (null === $startString) {
/** @var JournalRepositoryInterface $repository */
$repository = app(JournalRepositoryInterface::class);
$repository->setUser($this->getUser());
$first = $repository->firstNull();
if (null !== $first) {
$startDate = $first->date;
}
}
if (null !== $startString && '' !== $startString) {
$startDate = Carbon::createFromFormat('Y-m-d', $startString);
}
// parse end date
$endDate = Carbon::now();
$endString = $this->option('end_date');
if (null !== $endString && '' !== $endString) {
$endDate = Carbon::createFromFormat('Y-m-d', $endString);
}
if ($startDate > $endDate) {
[$endDate, $startDate] = [$startDate, $endDate];
}
$this->startDate = $startDate;
$this->endDate = $endDate;
}
/**
*/
private function grabAllRules(): void
{
$this->groups = $this->ruleGroupRepository->getActiveGroups();
}
/**
* @param Rule $rule
* @param RuleGroup $group
* @return bool
*/
private function includeRule(Rule $rule, RuleGroup $group): bool
{
return in_array($group->id, $this->ruleGroupSelection, true) ||
in_array($rule->id, $this->ruleSelection, true) ||
$this->allRules;
}
/**
* @return array
*/
private function getRulesToApply(): array
{
$rulesToApply = [];
/** @var RuleGroup $group */
foreach ($this->groups as $group) {
$rules = $this->ruleGroupRepository->getActiveStoreRules($group);
/** @var Rule $rule */
foreach ($rules as $rule) {
// if in rule selection, or group in selection or all rules, it's included.
$test = $this->includeRule($rule, $group);
if (true === $test) {
Log::debug(sprintf('Will include rule #%d "%s"', $rule->id, $rule->title));
$rulesToApply[] = $rule->id;
}
}
}
return $rulesToApply;
}
} }

View File

@@ -27,8 +27,8 @@ namespace FireflyIII\Console\Commands\Tools;
use Carbon\Carbon; use Carbon\Carbon;
use Exception; use Exception;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Support\Cronjobs\RecurringCronjob;
use FireflyIII\Support\Cronjobs\AutoBudgetCronjob; use FireflyIII\Support\Cronjobs\AutoBudgetCronjob;
use FireflyIII\Support\Cronjobs\RecurringCronjob;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use InvalidArgumentException; use InvalidArgumentException;
use Log; use Log;

View File

@@ -54,10 +54,10 @@ class AccountCurrencies extends Command
protected $signature = 'firefly-iii:account-currencies {--F|force : Force the execution of this command.}'; protected $signature = 'firefly-iii:account-currencies {--F|force : Force the execution of this command.}';
/** @var AccountRepositoryInterface */ /** @var AccountRepositoryInterface */
private $accountRepos; private $accountRepos;
/** @var UserRepositoryInterface */
private $userRepos;
/** @var int */ /** @var int */
private $count; private $count;
/** @var UserRepositoryInterface */
private $userRepos;
/** /**
* Each (asset) account must have a reference to a preferred currency. If the account does not have one, it's forced upon the account. * Each (asset) account must have a reference to a preferred currency. If the account does not have one, it's forced upon the account.
@@ -90,20 +90,6 @@ class AccountCurrencies extends Command
return 0; return 0;
} }
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
* @codeCoverageIgnore
*/
private function stupidLaravel(): void
{
$this->accountRepos = app(AccountRepositoryInterface::class);
$this->userRepos = app(UserRepositoryInterface::class);
$this->count = 0;
}
/** /**
* @return bool * @return bool
*/ */
@@ -117,7 +103,6 @@ class AccountCurrencies extends Command
return false; // @codeCoverageIgnore return false; // @codeCoverageIgnore
} }
/** /**
* *
*/ */
@@ -126,6 +111,20 @@ class AccountCurrencies extends Command
app('fireflyconfig')->set(self::CONFIG_NAME, true); app('fireflyconfig')->set(self::CONFIG_NAME, true);
} }
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
* @codeCoverageIgnore
*/
private function stupidLaravel(): void
{
$this->accountRepos = app(AccountRepositoryInterface::class);
$this->userRepos = app(UserRepositoryInterface::class);
$this->count = 0;
}
/** /**
* @param Account $account * @param Account $account
* @param TransactionCurrency $currency * @param TransactionCurrency $currency

View File

@@ -59,21 +59,21 @@ class MigrateToGroups extends Command
* @var string * @var string
*/ */
protected $signature = 'firefly-iii:migrate-to-groups {--F|force : Force the migration, even if it fired before.}'; protected $signature = 'firefly-iii:migrate-to-groups {--F|force : Force the migration, even if it fired before.}';
/** @var JournalCLIRepositoryInterface */
private $cliRepository;
private $count;
/** @var TransactionGroupFactory */ /** @var TransactionGroupFactory */
private $groupFactory; private $groupFactory;
/** @var JournalRepositoryInterface */ /** @var JournalRepositoryInterface */
private $journalRepository; private $journalRepository;
/** @var JournalCLIRepositoryInterface */
private $cliRepository;
/** @var JournalDestroyService */ /** @var JournalDestroyService */
private $service; private $service;
private $count;
/** /**
* Execute the console command. * Execute the console command.
* *
* @return int
* @throws Exception * @throws Exception
* @return int
*/ */
public function handle(): int public function handle(): int
{ {
@@ -116,22 +116,6 @@ class MigrateToGroups extends Command
return 0; return 0;
} }
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
* @codeCoverageIgnore
*/
private function stupidLaravel(): void
{
$this->count = 0;
$this->journalRepository = app(JournalRepositoryInterface::class);
$this->service = app(JournalDestroyService::class);
$this->groupFactory = app(TransactionGroupFactory::class);
$this->cliRepository = app(JournalCLIRepositoryInterface::class);
}
/** /**
* @param TransactionJournal $journal * @param TransactionJournal $journal
* @param Transaction $transaction * @param Transaction $transaction
@@ -168,6 +152,72 @@ class MigrateToGroups extends Command
); );
} }
/**
* @param Transaction $left
* @param Transaction $right
*
* @return int|null
*/
private function getTransactionBudget(Transaction $left, Transaction $right): ?int
{
Log::debug('Now in getTransactionBudget()');
// try to get a budget ID from the left transaction:
/** @var Budget $budget */
$budget = $left->budgets()->first();
if (null !== $budget) {
Log::debug(sprintf('Return budget #%d, from transaction #%d', $budget->id, $left->id));
return (int) $budget->id;
}
// try to get a budget ID from the right transaction:
/** @var Budget $budget */
$budget = $right->budgets()->first();
if (null !== $budget) {
Log::debug(sprintf('Return budget #%d, from transaction #%d', $budget->id, $right->id));
return (int) $budget->id;
}
Log::debug('Neither left or right have a budget, return NULL');
// if all fails, return NULL.
return null;
}
/**
* @param Transaction $left
* @param Transaction $right
*
* @return int|null
*/
private function getTransactionCategory(Transaction $left, Transaction $right): ?int
{
Log::debug('Now in getTransactionCategory()');
// try to get a category ID from the left transaction:
/** @var Category $category */
$category = $left->categories()->first();
if (null !== $category) {
Log::debug(sprintf('Return category #%d, from transaction #%d', $category->id, $left->id));
return (int) $category->id;
}
// try to get a category ID from the left transaction:
/** @var Category $category */
$category = $right->categories()->first();
if (null !== $category) {
Log::debug(sprintf('Return category #%d, from transaction #%d', $category->id, $category->id));
return (int) $category->id;
}
Log::debug('Neither left or right have a category, return NULL');
// if all fails, return NULL.
return null;
}
/** /**
* @param array $array * @param array $array
*/ */
@@ -383,72 +433,6 @@ class MigrateToGroups extends Command
); );
} }
/**
* @param Transaction $left
* @param Transaction $right
*
* @return int|null
*/
private function getTransactionBudget(Transaction $left, Transaction $right): ?int
{
Log::debug('Now in getTransactionBudget()');
// try to get a budget ID from the left transaction:
/** @var Budget $budget */
$budget = $left->budgets()->first();
if (null !== $budget) {
Log::debug(sprintf('Return budget #%d, from transaction #%d', $budget->id, $left->id));
return (int)$budget->id;
}
// try to get a budget ID from the right transaction:
/** @var Budget $budget */
$budget = $right->budgets()->first();
if (null !== $budget) {
Log::debug(sprintf('Return budget #%d, from transaction #%d', $budget->id, $right->id));
return (int)$budget->id;
}
Log::debug('Neither left or right have a budget, return NULL');
// if all fails, return NULL.
return null;
}
/**
* @param Transaction $left
* @param Transaction $right
*
* @return int|null
*/
private function getTransactionCategory(Transaction $left, Transaction $right): ?int
{
Log::debug('Now in getTransactionCategory()');
// try to get a category ID from the left transaction:
/** @var Category $category */
$category = $left->categories()->first();
if (null !== $category) {
Log::debug(sprintf('Return category #%d, from transaction #%d', $category->id, $left->id));
return (int)$category->id;
}
// try to get a category ID from the left transaction:
/** @var Category $category */
$category = $right->categories()->first();
if (null !== $category) {
Log::debug(sprintf('Return category #%d, from transaction #%d', $category->id, $category->id));
return (int)$category->id;
}
Log::debug('Neither left or right have a category, return NULL');
// if all fails, return NULL.
return null;
}
/** /**
* *
*/ */
@@ -456,4 +440,20 @@ class MigrateToGroups extends Command
{ {
app('fireflyconfig')->set(self::CONFIG_NAME, true); app('fireflyconfig')->set(self::CONFIG_NAME, true);
} }
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
* @codeCoverageIgnore
*/
private function stupidLaravel(): void
{
$this->count = 0;
$this->journalRepository = app(JournalRepositoryInterface::class);
$this->service = app(JournalDestroyService::class);
$this->groupFactory = app(TransactionGroupFactory::class);
$this->cliRepository = app(JournalCLIRepositoryInterface::class);
}
} }

View File

@@ -53,22 +53,21 @@ class MigrateToRules extends Command
* @var string * @var string
*/ */
protected $signature = 'firefly-iii:bills-to-rules {--F|force : Force the execution of this command.}'; protected $signature = 'firefly-iii:bills-to-rules {--F|force : Force the execution of this command.}';
/** @var UserRepositoryInterface */
private $userRepository;
/** @var RuleGroupRepositoryInterface */
private $ruleGroupRepository;
/** @var BillRepositoryInterface */ /** @var BillRepositoryInterface */
private $billRepository; private $billRepository;
private $count;
/** @var RuleGroupRepositoryInterface */
private $ruleGroupRepository;
/** @var RuleRepositoryInterface */ /** @var RuleRepositoryInterface */
private $ruleRepository; private $ruleRepository;
private $count; /** @var UserRepositoryInterface */
private $userRepository;
/** /**
* Execute the console command. * Execute the console command.
* *
* @return int
* @throws FireflyException * @throws FireflyException
* @return int
*/ */
public function handle(): int public function handle(): int
{ {
@@ -103,22 +102,6 @@ class MigrateToRules extends Command
return 0; return 0;
} }
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
* @codeCoverageIgnore
*/
private function stupidLaravel(): void
{
$this->count = 0;
$this->userRepository = app(UserRepositoryInterface::class);
$this->ruleGroupRepository = app(RuleGroupRepositoryInterface::class);
$this->billRepository = app(BillRepositoryInterface::class);
$this->ruleRepository = app(RuleRepositoryInterface::class);
}
/** /**
* @return bool * @return bool
*/ */
@@ -140,42 +123,6 @@ class MigrateToRules extends Command
app('fireflyconfig')->set(self::CONFIG_NAME, true); app('fireflyconfig')->set(self::CONFIG_NAME, true);
} }
/**
* Migrate bills to new rule structure for a specific user.
*
* @param User $user
* @throws FireflyException
*/
private function migrateUser(User $user): void
{
$this->ruleGroupRepository->setUser($user);
$this->billRepository->setUser($user);
$this->ruleRepository->setUser($user);
/** @var Preference $lang */
$lang = app('preferences')->getForUser($user, 'language', 'en_US');
$groupTitle = (string)trans('firefly.rulegroup_for_bills_title', [], $lang->data);
$ruleGroup = $this->ruleGroupRepository->findByTitle($groupTitle);
//$currency = $this->getCurrency($user);
if (null === $ruleGroup) {
$ruleGroup = $this->ruleGroupRepository->store(
[
'title' => (string)trans('firefly.rulegroup_for_bills_title', [], $lang->data),
'description' => (string)trans('firefly.rulegroup_for_bills_description', [], $lang->data),
'active' => true,
]
);
}
$bills = $this->billRepository->getBills();
/** @var Bill $bill */
foreach ($bills as $bill) {
$this->migrateBill($ruleGroup, $bill, $lang);
}
}
/** /**
* @param RuleGroup $ruleGroup * @param RuleGroup $ruleGroup
* @param Bill $bill * @param Bill $bill
@@ -246,4 +193,57 @@ class MigrateToRules extends Command
$this->billRepository->update($bill, $newBillData); $this->billRepository->update($bill, $newBillData);
$this->count++; $this->count++;
} }
/**
* Migrate bills to new rule structure for a specific user.
*
* @param User $user
*
* @throws FireflyException
*/
private function migrateUser(User $user): void
{
$this->ruleGroupRepository->setUser($user);
$this->billRepository->setUser($user);
$this->ruleRepository->setUser($user);
/** @var Preference $lang */
$lang = app('preferences')->getForUser($user, 'language', 'en_US');
$groupTitle = (string) trans('firefly.rulegroup_for_bills_title', [], $lang->data);
$ruleGroup = $this->ruleGroupRepository->findByTitle($groupTitle);
//$currency = $this->getCurrency($user);
if (null === $ruleGroup) {
$ruleGroup = $this->ruleGroupRepository->store(
[
'title' => (string) trans('firefly.rulegroup_for_bills_title', [], $lang->data),
'description' => (string) trans('firefly.rulegroup_for_bills_description', [], $lang->data),
'active' => true,
]
);
}
$bills = $this->billRepository->getBills();
/** @var Bill $bill */
foreach ($bills as $bill) {
$this->migrateBill($ruleGroup, $bill, $lang);
}
}
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
* @codeCoverageIgnore
*/
private function stupidLaravel(): void
{
$this->count = 0;
$this->userRepository = app(UserRepositoryInterface::class);
$this->ruleGroupRepository = app(RuleGroupRepositoryInterface::class);
$this->billRepository = app(BillRepositoryInterface::class);
$this->ruleRepository = app(RuleRepositoryInterface::class);
}
} }

View File

@@ -57,14 +57,14 @@ class OtherCurrenciesCorrections extends Command
private $accountCurrencies; private $accountCurrencies;
/** @var AccountRepositoryInterface */ /** @var AccountRepositoryInterface */
private $accountRepos; private $accountRepos;
/** @var CurrencyRepositoryInterface */
private $currencyRepos;
/** @var JournalRepositoryInterface */
private $journalRepos;
/** @var JournalCLIRepositoryInterface */ /** @var JournalCLIRepositoryInterface */
private $cliRepos; private $cliRepos;
/** @var int */ /** @var int */
private $count; private $count;
/** @var CurrencyRepositoryInterface */
private $currencyRepos;
/** @var JournalRepositoryInterface */
private $journalRepos;
/** /**
* Execute the console command. * Execute the console command.
@@ -93,23 +93,6 @@ class OtherCurrenciesCorrections extends Command
return 0; return 0;
} }
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
* @codeCoverageIgnore
*/
private function stupidLaravel(): void
{
$this->count = 0;
$this->accountCurrencies = [];
$this->accountRepos = app(AccountRepositoryInterface::class);
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
$this->journalRepos = app(JournalRepositoryInterface::class);
$this->cliRepos = app(JournalCLIRepositoryInterface::class);
}
/** /**
* @param Account $account * @param Account $account
* *
@@ -137,112 +120,6 @@ class OtherCurrenciesCorrections extends Command
return $currency; return $currency;
} }
/**
* @return bool
*/
private function isExecuted(): bool
{
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
if (null !== $configVar) {
return (bool)$configVar->data;
}
return false; // @codeCoverageIgnore
}
/**
*
*/
private function markAsExecuted(): void
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
/**
* @param TransactionJournal $journal
*/
private function updateJournalCurrency(TransactionJournal $journal): void
{
$this->accountRepos->setUser($journal->user);
$this->journalRepos->setUser($journal->user);
$this->currencyRepos->setUser($journal->user);
$this->cliRepos->setUser($journal->user);
$leadTransaction = $this->getLeadTransaction($journal);
if (null === $leadTransaction) {
// @codeCoverageIgnoreStart
$this->error(sprintf('Could not reliably determine which transaction is in the lead for transaction journal #%d.', $journal->id));
return;
// @codeCoverageIgnoreEnd
}
/** @var Account $account */
$account = $leadTransaction->account;
$currency = $this->getCurrency($account);
if (null === $currency) {
// @codeCoverageIgnoreStart
$this->error(sprintf(
'Account #%d ("%s") has no currency preference, so transaction journal #%d can\'t be corrected',
$account->id,
$account->name,
$journal->id
));
$this->count++;
return;
// @codeCoverageIgnoreEnd
}
// fix each transaction:
$journal->transactions->each(
static function (Transaction $transaction) use ($currency) {
if (null === $transaction->transaction_currency_id) {
$transaction->transaction_currency_id = $currency->id;
$transaction->save();
}
// when mismatch in transaction:
if (!((int)$transaction->transaction_currency_id === (int)$currency->id)) {
$transaction->foreign_currency_id = (int)$transaction->transaction_currency_id;
$transaction->foreign_amount = $transaction->amount;
$transaction->transaction_currency_id = $currency->id;
$transaction->save();
}
}
);
// also update the journal, of course:
$journal->transaction_currency_id = $currency->id;
$this->count++;
$journal->save();
}
/**
* This routine verifies that withdrawals, deposits and opening balances have the correct currency settings for
* the accounts they are linked to.
*
* Both source and destination must match the respective currency preference of the related asset account.
* So FF3 must verify all transactions.
*
*/
private function updateOtherJournalsCurrencies(): void
{
$set =
$this->cliRepos->getAllJournals(
[
TransactionType::WITHDRAWAL,
TransactionType::DEPOSIT,
TransactionType::OPENING_BALANCE,
TransactionType::RECONCILIATION,
]
);
/** @var TransactionJournal $journal */
foreach ($set as $journal) {
$this->updateJournalCurrency($journal);
}
}
/** /**
* Gets the transaction that determines the transaction that "leads" and will determine * Gets the transaction that determines the transaction that "leads" and will determine
* the currency to be used by all transactions, and the journal itself. * the currency to be used by all transactions, and the journal itself.
@@ -282,4 +159,129 @@ class OtherCurrenciesCorrections extends Command
return $lead; return $lead;
} }
/**
* @return bool
*/
private function isExecuted(): bool
{
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
if (null !== $configVar) {
return (bool) $configVar->data;
}
return false; // @codeCoverageIgnore
}
/**
*
*/
private function markAsExecuted(): void
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
* @codeCoverageIgnore
*/
private function stupidLaravel(): void
{
$this->count = 0;
$this->accountCurrencies = [];
$this->accountRepos = app(AccountRepositoryInterface::class);
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
$this->journalRepos = app(JournalRepositoryInterface::class);
$this->cliRepos = app(JournalCLIRepositoryInterface::class);
}
/**
* @param TransactionJournal $journal
*/
private function updateJournalCurrency(TransactionJournal $journal): void
{
$this->accountRepos->setUser($journal->user);
$this->journalRepos->setUser($journal->user);
$this->currencyRepos->setUser($journal->user);
$this->cliRepos->setUser($journal->user);
$leadTransaction = $this->getLeadTransaction($journal);
if (null === $leadTransaction) {
// @codeCoverageIgnoreStart
$this->error(sprintf('Could not reliably determine which transaction is in the lead for transaction journal #%d.', $journal->id));
return;
// @codeCoverageIgnoreEnd
}
/** @var Account $account */
$account = $leadTransaction->account;
$currency = $this->getCurrency($account);
if (null === $currency) {
// @codeCoverageIgnoreStart
$this->error(
sprintf(
'Account #%d ("%s") has no currency preference, so transaction journal #%d can\'t be corrected',
$account->id,
$account->name,
$journal->id
)
);
$this->count++;
return;
// @codeCoverageIgnoreEnd
}
// fix each transaction:
$journal->transactions->each(
static function (Transaction $transaction) use ($currency) {
if (null === $transaction->transaction_currency_id) {
$transaction->transaction_currency_id = $currency->id;
$transaction->save();
}
// when mismatch in transaction:
if (!((int) $transaction->transaction_currency_id === (int) $currency->id)) {
$transaction->foreign_currency_id = (int) $transaction->transaction_currency_id;
$transaction->foreign_amount = $transaction->amount;
$transaction->transaction_currency_id = $currency->id;
$transaction->save();
}
}
);
// also update the journal, of course:
$journal->transaction_currency_id = $currency->id;
$this->count++;
$journal->save();
}
/**
* This routine verifies that withdrawals, deposits and opening balances have the correct currency settings for
* the accounts they are linked to.
*
* Both source and destination must match the respective currency preference of the related asset account.
* So FF3 must verify all transactions.
*
*/
private function updateOtherJournalsCurrencies(): void
{
$set
= $this->cliRepos->getAllJournals(
[
TransactionType::WITHDRAWAL,
TransactionType::DEPOSIT,
TransactionType::OPENING_BALANCE,
TransactionType::RECONCILIATION,
]
);
/** @var TransactionJournal $journal */
foreach ($set as $journal) {
$this->updateJournalCurrency($journal);
}
}
} }

View File

@@ -50,15 +50,12 @@ class TransactionIdentifier extends Command
* @var string * @var string
*/ */
protected $signature = 'firefly-iii:transaction-identifiers {--F|force : Force the execution of this command.}'; protected $signature = 'firefly-iii:transaction-identifiers {--F|force : Force the execution of this command.}';
/** @var JournalRepositoryInterface */
private $journalRepository;
/** @var JournalCLIRepositoryInterface */ /** @var JournalCLIRepositoryInterface */
private $cliRepository; private $cliRepository;
/** @var int */ /** @var int */
private $count; private $count;
/** @var JournalRepositoryInterface */
private $journalRepository;
/** /**
* This method gives all transactions which are part of a split journal (so more than 2) a sort of "order" so they are easier * This method gives all transactions which are part of a split journal (so more than 2) a sort of "order" so they are easier
@@ -108,17 +105,36 @@ class TransactionIdentifier extends Command
} }
/** /**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is * @param Transaction $transaction
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should * @param array $exclude
* be called from the handle method instead of using the constructor to initialize the command.
* *
* @codeCoverageIgnore * @return Transaction|null
*/ */
private function stupidLaravel(): void private function findOpposing(Transaction $transaction, array $exclude): ?Transaction
{ {
$this->journalRepository = app(JournalRepositoryInterface::class); // find opposing:
$this->cliRepository = app(JournalCLIRepositoryInterface::class); $amount = bcmul((string) $transaction->amount, '-1');
$this->count = 0;
try {
/** @var Transaction $opposing */
$opposing = Transaction::where('transaction_journal_id', $transaction->transaction_journal_id)
->where('amount', $amount)->where('identifier', '=', 0)
->whereNotIn('id', $exclude)
->first();
// @codeCoverageIgnoreStart
} catch (QueryException $e) {
Log::error($e->getMessage());
$this->error('Firefly III could not find the "identifier" field in the "transactions" table.');
$this->error(sprintf('This field is required for Firefly III version %s to run.', config('firefly.version')));
$this->error('Please run "php artisan migrate" to add this field to the table.');
$this->info('Then, run "php artisan firefly:upgrade-database" to try again.');
return null;
}
// @codeCoverageIgnoreEnd
return $opposing;
} }
/** /**
@@ -142,6 +158,20 @@ class TransactionIdentifier extends Command
app('fireflyconfig')->set(self::CONFIG_NAME, true); app('fireflyconfig')->set(self::CONFIG_NAME, true);
} }
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
* @codeCoverageIgnore
*/
private function stupidLaravel(): void
{
$this->journalRepository = app(JournalRepositoryInterface::class);
$this->cliRepository = app(JournalCLIRepositoryInterface::class);
$this->count = 0;
}
/** /**
* Grab all positive transactions from this journal that are not deleted. for each one, grab the negative opposing one * Grab all positive transactions from this journal that are not deleted. for each one, grab the negative opposing one
* which has 0 as an identifier and give it the same identifier. * which has 0 as an identifier and give it the same identifier.
@@ -171,36 +201,4 @@ class TransactionIdentifier extends Command
} }
} }
/**
* @param Transaction $transaction
* @param array $exclude
* @return Transaction|null
*/
private function findOpposing(Transaction $transaction, array $exclude): ?Transaction
{
// find opposing:
$amount = bcmul((string)$transaction->amount, '-1');
try {
/** @var Transaction $opposing */
$opposing = Transaction::where('transaction_journal_id', $transaction->transaction_journal_id)
->where('amount', $amount)->where('identifier', '=', 0)
->whereNotIn('id', $exclude)
->first();
// @codeCoverageIgnoreStart
} catch (QueryException $e) {
Log::error($e->getMessage());
$this->error('Firefly III could not find the "identifier" field in the "transactions" table.');
$this->error(sprintf('This field is required for Firefly III version %s to run.', config('firefly.version')));
$this->error('Please run "php artisan migrate" to add this field to the table.');
$this->info('Then, run "php artisan firefly:upgrade-database" to try again.');
return null;
}
// @codeCoverageIgnoreEnd
return $opposing;
}
} }

View File

@@ -57,27 +57,26 @@ class TransferCurrenciesCorrections extends Command
private $accountCurrencies; private $accountCurrencies;
/** @var AccountRepositoryInterface */ /** @var AccountRepositoryInterface */
private $accountRepos; private $accountRepos;
/** @var CurrencyRepositoryInterface */
private $currencyRepos;
/** @var JournalRepositoryInterface */
private $journalRepos;
/** @var JournalCLIRepositoryInterface */ /** @var JournalCLIRepositoryInterface */
private $cliRepos; private $cliRepos;
/** @var int */ /** @var int */
private $count; private $count;
/** @var CurrencyRepositoryInterface */
/** @var Transaction The source transaction of the current journal. */ private $currencyRepos;
private $sourceTransaction;
/** @var Account The source account of the current journal. */
private $sourceAccount;
/** @var TransactionCurrency The currency preference of the source account of the current journal. */
private $sourceCurrency;
/** @var Transaction The destination transaction of the current journal. */
private $destinationTransaction;
/** @var Account The destination account of the current journal. */ /** @var Account The destination account of the current journal. */
private $destinationAccount; private $destinationAccount;
/** @var TransactionCurrency The currency preference of the destination account of the current journal. */ /** @var TransactionCurrency The currency preference of the destination account of the current journal. */
private $destinationCurrency; private $destinationCurrency;
/** @var Transaction The destination transaction of the current journal. */
private $destinationTransaction;
/** @var JournalRepositoryInterface */
private $journalRepos;
/** @var Account The source account of the current journal. */
private $sourceAccount;
/** @var TransactionCurrency The currency preference of the source account of the current journal. */
private $sourceCurrency;
/** @var Transaction The source transaction of the current journal. */
private $sourceTransaction;
/** /**
* Execute the console command. * Execute the console command.
@@ -116,21 +115,216 @@ class TransferCurrenciesCorrections extends Command
} }
/** /**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is * The destination transaction must have a currency. If not, it will be added by
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should * taking it from the destination account's preference.
* be called from the handle method instead of using the constructor to initialize the command.
*
* @codeCoverageIgnore
*/ */
private function stupidLaravel(): void private function fixDestNoCurrency(): void
{ {
$this->count = 0; if (null === $this->destinationTransaction->transaction_currency_id && null !== $this->destinationCurrency) {
$this->accountRepos = app(AccountRepositoryInterface::class); $this->destinationTransaction
$this->currencyRepos = app(CurrencyRepositoryInterface::class); ->transaction_currency_id
$this->journalRepos = app(JournalRepositoryInterface::class); = (int) $this->destinationCurrency->id;
$this->cliRepos = app(JournalCLIRepositoryInterface::class); $message = sprintf(
$this->accountCurrencies = []; 'Transaction #%d has no currency setting, now set to %s.',
$this->resetInformation(); $this->destinationTransaction->id,
$this->destinationCurrency->code
);
Log::debug($message);
$this->line($message);
$this->count++;
$this->destinationTransaction->save();
}
}
/**
* If the foreign amount of the destination transaction is null, but that of the other isn't, use this piece of code
* to restore it.
*/
private function fixDestNullForeignAmount(): void
{
if (null === $this->destinationTransaction->foreign_amount && null !== $this->sourceTransaction->foreign_amount) {
$this->destinationTransaction->foreign_amount = bcmul((string) $this->sourceTransaction->foreign_amount, '-1');
$this->destinationTransaction->save();
$this->count++;
Log::debug(
sprintf(
'Restored foreign amount of destination transaction #%d to %s',
$this->destinationTransaction->id,
$this->destinationTransaction->foreign_amount
)
);
}
}
/**
* The destination transaction must have the correct currency. If not, it will be set by
* taking it from the destination account's preference.
*/
private function fixDestinationUnmatchedCurrency(): void
{
if (null !== $this->destinationCurrency
&& null === $this->destinationTransaction->foreign_amount
&& (int) $this->destinationTransaction->transaction_currency_id !== (int) $this->destinationCurrency->id
) {
$message = sprintf(
'Transaction #%d has a currency setting #%d that should be #%d. Amount remains %s, currency is changed.',
$this->destinationTransaction->id,
$this->destinationTransaction->transaction_currency_id,
$this->destinationAccount->id,
$this->destinationTransaction->amount
);
Log::debug($message);
$this->line($message);
$this->count++;
$this->destinationTransaction->transaction_currency_id = (int) $this->destinationCurrency->id;
$this->destinationTransaction->save();
}
}
/**
* If the destination account currency is the same as the source currency,
* both foreign_amount and foreign_currency_id fields must be NULL
* for both transactions (because foreign currency info would not make sense)
*
*/
private function fixInvalidForeignCurrency(): void
{
if ((int) $this->destinationCurrency->id === (int) $this->sourceCurrency->id) {
// update both transactions to match:
$this->sourceTransaction->foreign_amount = null;
$this->sourceTransaction->foreign_currency_id = null;
$this->destinationTransaction->foreign_amount = null;
$this->destinationTransaction->foreign_currency_id = null;
$this->sourceTransaction->save();
$this->destinationTransaction->save();
Log::debug(
sprintf(
'Currency for account "%s" is %s, and currency for account "%s" is also
%s, so transactions #%d and #%d has been verified to be to %s exclusively.',
$this->destinationAccount->name,
$this->destinationCurrency->code,
$this->sourceAccount->name,
$this->sourceCurrency->code,
$this->sourceTransaction->id,
$this->destinationTransaction->id,
$this->sourceCurrency->code
)
);
}
}
/**
* If destination account currency is different from source account currency,
* then both transactions must get the source account's currency as normal currency
* and the opposing account's currency as foreign currency.
*/
private function fixMismatchedForeignCurrency(): void
{
if ((int) $this->sourceCurrency->id !== (int) $this->destinationCurrency->id) {
$this->sourceTransaction->transaction_currency_id = $this->sourceCurrency->id;
$this->sourceTransaction->foreign_currency_id = $this->destinationCurrency->id;
$this->destinationTransaction->transaction_currency_id = $this->sourceCurrency->id;
$this->destinationTransaction->foreign_currency_id = $this->destinationCurrency->id;
$this->sourceTransaction->save();
$this->destinationTransaction->save();
$this->count++;
Log::debug(sprintf('Verified foreign currency ID of transaction #%d and #%d', $this->sourceTransaction->id, $this->destinationTransaction->id));
}
}
/**
* The source transaction must have a currency. If not, it will be added by
* taking it from the source account's preference.
*/
private function fixSourceNoCurrency(): void
{
if (null === $this->sourceTransaction->transaction_currency_id && null !== $this->sourceCurrency) {
$this->sourceTransaction
->transaction_currency_id
= (int) $this->sourceCurrency->id;
$message = sprintf(
'Transaction #%d has no currency setting, now set to %s.',
$this->sourceTransaction->id,
$this->sourceCurrency->code
);
Log::debug($message);
$this->line($message);
$this->count++;
$this->sourceTransaction->save();
}
}
/**
* If the foreign amount of the source transaction is null, but that of the other isn't, use this piece of code
* to restore it.
*/
private function fixSourceNullForeignAmount(): void
{
if (null === $this->sourceTransaction->foreign_amount && null !== $this->destinationTransaction->foreign_amount) {
$this->sourceTransaction->foreign_amount = bcmul((string) $this->destinationTransaction->foreign_amount, '-1');
$this->sourceTransaction->save();
$this->count++;
Log::debug(
sprintf(
'Restored foreign amount of source transaction #%d to %s',
$this->sourceTransaction->id,
$this->sourceTransaction->foreign_amount
)
);
}
}
/**
* The source transaction must have the correct currency. If not, it will be set by
* taking it from the source account's preference.
*/
private function fixSourceUnmatchedCurrency(): void
{
if (null !== $this->sourceCurrency
&& null === $this->sourceTransaction->foreign_amount
&& (int) $this->sourceTransaction->transaction_currency_id !== (int) $this->sourceCurrency->id
) {
$message = sprintf(
'Transaction #%d has a currency setting #%d that should be #%d. Amount remains %s, currency is changed.',
$this->sourceTransaction->id,
$this->sourceTransaction->transaction_currency_id,
$this->sourceAccount->id,
$this->sourceTransaction->amount
);
Log::debug($message);
$this->line($message);
$this->count++;
$this->sourceTransaction->transaction_currency_id = (int) $this->sourceCurrency->id;
$this->sourceTransaction->save();
}
}
/**
* This method makes sure that the transaction journal uses the currency given in the source transaction.
*
* @param TransactionJournal $journal
*/
private function fixTransactionJournalCurrency(TransactionJournal $journal): void
{
if ((int) $journal->transaction_currency_id !== (int) $this->sourceCurrency->id) {
$oldCurrencyCode = $journal->transactionCurrency->code ?? '(nothing)';
$journal->transaction_currency_id = $this->sourceCurrency->id;
$message = sprintf(
'Transfer #%d ("%s") has been updated to use %s instead of %s.',
$journal->id,
$journal->description,
$this->sourceCurrency->code,
$oldCurrencyCode
);
$this->count++;
$this->line($message);
Log::debug($message);
$journal->save();
}
} }
/** /**
@@ -162,6 +356,20 @@ class TransferCurrenciesCorrections extends Command
return $result; return $result;
} }
/**
* Extract destination transaction, destination account + destination account currency from the journal.
*
* @param TransactionJournal $journal
*
* @codeCoverageIgnore
*/
private function getDestinationInformation(TransactionJournal $journal): void
{
$this->destinationTransaction = $this->getDestinationTransaction($journal);
$this->destinationAccount = null === $this->destinationTransaction ? null : $this->destinationTransaction->account;
$this->destinationCurrency = null === $this->destinationAccount ? null : $this->getCurrency($this->destinationAccount);
}
/** /**
* @param TransactionJournal $transfer * @param TransactionJournal $transfer
* *
@@ -173,6 +381,20 @@ class TransferCurrenciesCorrections extends Command
return $transfer->transactions()->where('amount', '>', 0)->first(); return $transfer->transactions()->where('amount', '>', 0)->first();
} }
/**
* Extract source transaction, source account + source account currency from the journal.
*
* @param TransactionJournal $journal
*
* @codeCoverageIgnore
*/
private function getSourceInformation(TransactionJournal $journal): void
{
$this->sourceTransaction = $this->getSourceTransaction($journal);
$this->sourceAccount = null === $this->sourceTransaction ? null : $this->sourceTransaction->account;
$this->sourceCurrency = null === $this->sourceAccount ? null : $this->getCurrency($this->sourceAccount);
}
/** /**
* @param TransactionJournal $transfer * @param TransactionJournal $transfer
* *
@@ -184,6 +406,19 @@ class TransferCurrenciesCorrections extends Command
return $transfer->transactions()->where('amount', '<', 0)->first(); return $transfer->transactions()->where('amount', '<', 0)->first();
} }
/**
* Is either the source or destination transaction NULL?
*
* @return bool
* @codeCoverageIgnore
*/
private function isEmptyTransactions(): bool
{
return null === $this->sourceTransaction || null === $this->destinationTransaction
|| null === $this->sourceAccount
|| null === $this->destinationAccount;
}
/** /**
* @return bool * @return bool
*/ */
@@ -197,6 +432,50 @@ class TransferCurrenciesCorrections extends Command
return false; // @codeCoverageIgnore return false; // @codeCoverageIgnore
} }
/**
* @return bool
* @codeCoverageIgnore
*/
private function isNoCurrencyPresent(): bool
{
// source account must have a currency preference.
if (null === $this->sourceCurrency) {
$message = sprintf('Account #%d ("%s") must have currency preference but has none.', $this->sourceAccount->id, $this->sourceAccount->name);
Log::error($message);
$this->error($message);
return true;
}
// destination account must have a currency preference.
if (null === $this->destinationCurrency) {
$message = sprintf(
'Account #%d ("%s") must have currency preference but has none.',
$this->destinationAccount->id,
$this->destinationAccount->name
);
Log::error($message);
$this->error($message);
return true;
}
return false;
}
/**
* Is this a split transaction journal?
*
* @param TransactionJournal $transfer
*
* @return bool
* @codeCoverageIgnore
*/
private function isSplitJournal(TransactionJournal $transfer): bool
{
return $transfer->transactions->count() > 2;
}
/** /**
* *
*/ */
@@ -206,27 +485,18 @@ class TransferCurrenciesCorrections extends Command
} }
/** /**
* This method makes sure that the transaction journal uses the currency given in the source transaction. * Reset all the class fields for the current transfer.
* *
* @param TransactionJournal $journal * @codeCoverageIgnore
*/ */
private function fixTransactionJournalCurrency(TransactionJournal $journal): void private function resetInformation(): void
{ {
if ((int)$journal->transaction_currency_id !== (int)$this->sourceCurrency->id) { $this->sourceTransaction = null;
$oldCurrencyCode = $journal->transactionCurrency->code ?? '(nothing)'; $this->sourceAccount = null;
$journal->transaction_currency_id = $this->sourceCurrency->id; $this->sourceCurrency = null;
$message = sprintf( $this->destinationTransaction = null;
'Transfer #%d ("%s") has been updated to use %s instead of %s.', $this->destinationAccount = null;
$journal->id, $this->destinationCurrency = null;
$journal->description,
$this->sourceCurrency->code,
$oldCurrencyCode
);
$this->count++;
$this->line($message);
Log::debug($message);
$journal->save();
}
} }
/** /**
@@ -249,43 +519,21 @@ class TransferCurrenciesCorrections extends Command
} }
/** /**
* Reset all the class fields for the current transfer. * Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* @codeCoverageIgnore * executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
*/ * be called from the handle method instead of using the constructor to initialize the command.
private function resetInformation(): void
{
$this->sourceTransaction = null;
$this->sourceAccount = null;
$this->sourceCurrency = null;
$this->destinationTransaction = null;
$this->destinationAccount = null;
$this->destinationCurrency = null;
}
/**
* Extract source transaction, source account + source account currency from the journal.
* *
* @param TransactionJournal $journal
* @codeCoverageIgnore * @codeCoverageIgnore
*/ */
private function getSourceInformation(TransactionJournal $journal): void private function stupidLaravel(): void
{ {
$this->sourceTransaction = $this->getSourceTransaction($journal); $this->count = 0;
$this->sourceAccount = null === $this->sourceTransaction ? null : $this->sourceTransaction->account; $this->accountRepos = app(AccountRepositoryInterface::class);
$this->sourceCurrency = null === $this->sourceAccount ? null : $this->getCurrency($this->sourceAccount); $this->currencyRepos = app(CurrencyRepositoryInterface::class);
} $this->journalRepos = app(JournalRepositoryInterface::class);
$this->cliRepos = app(JournalCLIRepositoryInterface::class);
/** $this->accountCurrencies = [];
* Extract destination transaction, destination account + destination account currency from the journal. $this->resetInformation();
*
* @param TransactionJournal $journal
* @codeCoverageIgnore
*/
private function getDestinationInformation(TransactionJournal $journal): void
{
$this->destinationTransaction = $this->getDestinationTransaction($journal);
$this->destinationAccount = null === $this->destinationTransaction ? null : $this->destinationTransaction->account;
$this->destinationCurrency = null === $this->destinationAccount ? null : $this->getCurrency($this->destinationAccount);
} }
/** /**
@@ -352,241 +600,4 @@ class TransferCurrenciesCorrections extends Command
// fix journal itself: // fix journal itself:
$this->fixTransactionJournalCurrency($transfer); $this->fixTransactionJournalCurrency($transfer);
} }
/**
* The source transaction must have a currency. If not, it will be added by
* taking it from the source account's preference.
*/
private function fixSourceNoCurrency(): void
{
if (null === $this->sourceTransaction->transaction_currency_id && null !== $this->sourceCurrency) {
$this->sourceTransaction
->transaction_currency_id = (int)$this->sourceCurrency->id;
$message = sprintf(
'Transaction #%d has no currency setting, now set to %s.',
$this->sourceTransaction->id,
$this->sourceCurrency->code
);
Log::debug($message);
$this->line($message);
$this->count++;
$this->sourceTransaction->save();
}
}
/**
* The destination transaction must have a currency. If not, it will be added by
* taking it from the destination account's preference.
*/
private function fixDestNoCurrency(): void
{
if (null === $this->destinationTransaction->transaction_currency_id && null !== $this->destinationCurrency) {
$this->destinationTransaction
->transaction_currency_id = (int)$this->destinationCurrency->id;
$message = sprintf(
'Transaction #%d has no currency setting, now set to %s.',
$this->destinationTransaction->id,
$this->destinationCurrency->code
);
Log::debug($message);
$this->line($message);
$this->count++;
$this->destinationTransaction->save();
}
}
/**
* The source transaction must have the correct currency. If not, it will be set by
* taking it from the source account's preference.
*/
private function fixSourceUnmatchedCurrency(): void
{
if (null !== $this->sourceCurrency &&
null === $this->sourceTransaction->foreign_amount &&
(int)$this->sourceTransaction->transaction_currency_id !== (int)$this->sourceCurrency->id
) {
$message = sprintf(
'Transaction #%d has a currency setting #%d that should be #%d. Amount remains %s, currency is changed.',
$this->sourceTransaction->id,
$this->sourceTransaction->transaction_currency_id,
$this->sourceAccount->id,
$this->sourceTransaction->amount
);
Log::debug($message);
$this->line($message);
$this->count++;
$this->sourceTransaction->transaction_currency_id = (int)$this->sourceCurrency->id;
$this->sourceTransaction->save();
}
}
/**
* The destination transaction must have the correct currency. If not, it will be set by
* taking it from the destination account's preference.
*/
private function fixDestinationUnmatchedCurrency(): void
{
if (null !== $this->destinationCurrency &&
null === $this->destinationTransaction->foreign_amount &&
(int)$this->destinationTransaction->transaction_currency_id !== (int)$this->destinationCurrency->id
) {
$message = sprintf(
'Transaction #%d has a currency setting #%d that should be #%d. Amount remains %s, currency is changed.',
$this->destinationTransaction->id,
$this->destinationTransaction->transaction_currency_id,
$this->destinationAccount->id,
$this->destinationTransaction->amount
);
Log::debug($message);
$this->line($message);
$this->count++;
$this->destinationTransaction->transaction_currency_id = (int)$this->destinationCurrency->id;
$this->destinationTransaction->save();
}
}
/**
* Is this a split transaction journal?
*
* @param TransactionJournal $transfer
* @return bool
* @codeCoverageIgnore
*/
private function isSplitJournal(TransactionJournal $transfer): bool
{
return $transfer->transactions->count() > 2;
}
/**
* Is either the source or destination transaction NULL?
* @return bool
* @codeCoverageIgnore
*/
private function isEmptyTransactions(): bool
{
return null === $this->sourceTransaction || null === $this->destinationTransaction ||
null === $this->sourceAccount || null === $this->destinationAccount;
}
/**
* If the destination account currency is the same as the source currency,
* both foreign_amount and foreign_currency_id fields must be NULL
* for both transactions (because foreign currency info would not make sense)
*
*/
private function fixInvalidForeignCurrency(): void
{
if ((int)$this->destinationCurrency->id === (int)$this->sourceCurrency->id) {
// update both transactions to match:
$this->sourceTransaction->foreign_amount = null;
$this->sourceTransaction->foreign_currency_id = null;
$this->destinationTransaction->foreign_amount = null;
$this->destinationTransaction->foreign_currency_id = null;
$this->sourceTransaction->save();
$this->destinationTransaction->save();
Log::debug(
sprintf(
'Currency for account "%s" is %s, and currency for account "%s" is also
%s, so transactions #%d and #%d has been verified to be to %s exclusively.',
$this->destinationAccount->name,
$this->destinationCurrency->code,
$this->sourceAccount->name,
$this->sourceCurrency->code,
$this->sourceTransaction->id,
$this->destinationTransaction->id,
$this->sourceCurrency->code
)
);
}
}
/**
* If destination account currency is different from source account currency,
* then both transactions must get the source account's currency as normal currency
* and the opposing account's currency as foreign currency.
*/
private function fixMismatchedForeignCurrency(): void
{
if ((int)$this->sourceCurrency->id !== (int)$this->destinationCurrency->id) {
$this->sourceTransaction->transaction_currency_id = $this->sourceCurrency->id;
$this->sourceTransaction->foreign_currency_id = $this->destinationCurrency->id;
$this->destinationTransaction->transaction_currency_id = $this->sourceCurrency->id;
$this->destinationTransaction->foreign_currency_id = $this->destinationCurrency->id;
$this->sourceTransaction->save();
$this->destinationTransaction->save();
$this->count++;
Log::debug(sprintf('Verified foreign currency ID of transaction #%d and #%d', $this->sourceTransaction->id, $this->destinationTransaction->id));
}
}
/**
* If the foreign amount of the source transaction is null, but that of the other isn't, use this piece of code
* to restore it.
*/
private function fixSourceNullForeignAmount(): void
{
if (null === $this->sourceTransaction->foreign_amount && null !== $this->destinationTransaction->foreign_amount) {
$this->sourceTransaction->foreign_amount = bcmul((string)$this->destinationTransaction->foreign_amount, '-1');
$this->sourceTransaction->save();
$this->count++;
Log::debug(sprintf(
'Restored foreign amount of source transaction #%d to %s',
$this->sourceTransaction->id,
$this->sourceTransaction->foreign_amount
));
}
}
/**
* If the foreign amount of the destination transaction is null, but that of the other isn't, use this piece of code
* to restore it.
*/
private function fixDestNullForeignAmount(): void
{
if (null === $this->destinationTransaction->foreign_amount && null !== $this->sourceTransaction->foreign_amount) {
$this->destinationTransaction->foreign_amount = bcmul((string)$this->sourceTransaction->foreign_amount, '-1');
$this->destinationTransaction->save();
$this->count++;
Log::debug(sprintf(
'Restored foreign amount of destination transaction #%d to %s',
$this->destinationTransaction->id,
$this->destinationTransaction->foreign_amount
));
}
}
/**
* @return bool
* @codeCoverageIgnore
*/
private function isNoCurrencyPresent(): bool
{
// source account must have a currency preference.
if (null === $this->sourceCurrency) {
$message = sprintf('Account #%d ("%s") must have currency preference but has none.', $this->sourceAccount->id, $this->sourceAccount->name);
Log::error($message);
$this->error($message);
return true;
}
// destination account must have a currency preference.
if (null === $this->destinationCurrency) {
$message = sprintf(
'Account #%d ("%s") must have currency preference but has none.',
$this->destinationAccount->id,
$this->destinationAccount->name
);
Log::error($message);
$this->error($message);
return true;
}
return false;
}
} }

View File

@@ -30,6 +30,7 @@ use Illuminate\Console\Command;
/** /**
* Class UpgradeDatabase * Class UpgradeDatabase
*
* @codeCoverageIgnore * @codeCoverageIgnore
*/ */
class UpgradeDatabase extends Command class UpgradeDatabase extends Command

View File

@@ -38,8 +38,8 @@ use Log;
trait VerifiesAccessToken trait VerifiesAccessToken
{ {
/** /**
* @return User
* @throws FireflyException * @throws FireflyException
* @return User
*/ */
public function getUser(): User public function getUser(): User
{ {