mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-05 04:03:26 +00:00
Update installation commands.
This commit is contained in:
@@ -89,6 +89,7 @@ class CorrectOpeningBalanceCurrencies extends Command
|
||||
}
|
||||
|
||||
Log::debug(sprintf('Done with %s', __METHOD__));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -133,6 +134,7 @@ class CorrectOpeningBalanceCurrencies extends Command
|
||||
$account = $transaction->account()->first();
|
||||
if (null !== $account && AccountType::INITIAL_BALANCE !== $account->accountType()->first()->type) {
|
||||
Log::debug(sprintf('Account of transaction #%d is opposite of IB account (%s).', $transaction->id, $account->accountType()->first()->type));
|
||||
|
||||
return $account;
|
||||
}
|
||||
}
|
||||
@@ -143,6 +145,7 @@ class CorrectOpeningBalanceCurrencies extends Command
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
* @return TransactionCurrency
|
||||
* @throws JsonException
|
||||
*/
|
||||
@@ -156,15 +159,16 @@ class CorrectOpeningBalanceCurrencies extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param TransactionJournal $journal
|
||||
* @param TransactionCurrency $currency
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function setCurrency(TransactionJournal $journal, TransactionCurrency $currency): int
|
||||
{
|
||||
Log::debug('Now in setCurrency');
|
||||
$count = 0;
|
||||
if ((int) $journal->transaction_currency_id !== (int) $currency->id) {
|
||||
if ((int)$journal->transaction_currency_id !== (int)$currency->id) {
|
||||
Log::debug(sprintf('Currency ID of journal #%d was #%d, now set to #%d', $journal->id, $journal->transaction_currency_id, $currency->id));
|
||||
$journal->transaction_currency_id = $currency->id;
|
||||
$journal->save();
|
||||
@@ -173,8 +177,10 @@ class CorrectOpeningBalanceCurrencies extends Command
|
||||
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($journal->transactions as $transaction) {
|
||||
if ((int) $transaction->transaction_currency_id !== (int) $currency->id) {
|
||||
Log::debug(sprintf('Currency ID of transaction #%d was #%d, now set to #%d', $transaction->id, $transaction->transaction_currency_id, $currency->id));
|
||||
if ((int)$transaction->transaction_currency_id !== (int)$currency->id) {
|
||||
Log::debug(
|
||||
sprintf('Currency ID of transaction #%d was #%d, now set to #%d', $transaction->id, $transaction->transaction_currency_id, $currency->id)
|
||||
);
|
||||
$transaction->transaction_currency_id = $currency->id;
|
||||
$transaction->save();
|
||||
$count = 1;
|
||||
|
@@ -50,8 +50,8 @@ class CreateAccessTokens extends Command
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @throws Exception
|
||||
* @return int
|
||||
* @throws Exception
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
|
@@ -50,9 +50,9 @@ class DeleteEmptyGroups extends Command
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
* @throws Exception;
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
|
@@ -62,6 +62,38 @@ class DeleteEmptyJournals extends Command
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete transactions and their journals if they have an uneven number of transactions.
|
||||
*/
|
||||
private function deleteUnevenJournals(): void
|
||||
{
|
||||
$set = Transaction
|
||||
::whereNull('deleted_at')
|
||||
->groupBy('transactions.transaction_journal_id')
|
||||
->get([DB::raw('COUNT(transactions.transaction_journal_id) as the_count'), 'transaction_journal_id']);
|
||||
$total = 0;
|
||||
foreach ($set as $row) {
|
||||
$count = (int)$row->the_count;
|
||||
if (1 === $count % 2) {
|
||||
// uneven number, delete journal and transactions:
|
||||
try {
|
||||
TransactionJournal::find((int)$row->transaction_journal_id)->delete();
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (Exception $e) {
|
||||
Log::info(sprintf('Could not delete journal: %s', $e->getMessage()));
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
Transaction::where('transaction_journal_id', (int)$row->transaction_journal_id)->delete();
|
||||
$this->info(sprintf('Deleted transaction journal #%d because it had an uneven number of transactions.', $row->transaction_journal_id));
|
||||
$total++;
|
||||
}
|
||||
}
|
||||
if (0 === $total) {
|
||||
$this->info('No uneven transaction journals.');
|
||||
}
|
||||
}
|
||||
|
||||
private function deleteEmptyJournals(): void
|
||||
{
|
||||
$start = microtime(true);
|
||||
@@ -90,36 +122,4 @@ class DeleteEmptyJournals extends Command
|
||||
$this->info(sprintf('Verified empty journals in %s seconds', $end));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete transactions and their journals if they have an uneven number of transactions.
|
||||
*/
|
||||
private function deleteUnevenJournals(): void
|
||||
{
|
||||
$set = Transaction
|
||||
::whereNull('deleted_at')
|
||||
->groupBy('transactions.transaction_journal_id')
|
||||
->get([DB::raw('COUNT(transactions.transaction_journal_id) as the_count'), 'transaction_journal_id']);
|
||||
$total = 0;
|
||||
foreach ($set as $row) {
|
||||
$count = (int) $row->the_count;
|
||||
if (1 === $count % 2) {
|
||||
// uneven number, delete journal and transactions:
|
||||
try {
|
||||
TransactionJournal::find((int) $row->transaction_journal_id)->delete();
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (Exception $e) {
|
||||
Log::info(sprintf('Could not delete journal: %s', $e->getMessage()));
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
Transaction::where('transaction_journal_id', (int) $row->transaction_journal_id)->delete();
|
||||
$this->info(sprintf('Deleted transaction journal #%d because it had an uneven number of transactions.', $row->transaction_journal_id));
|
||||
$total++;
|
||||
}
|
||||
}
|
||||
if (0 === $total) {
|
||||
$this->info('No uneven transaction journals.');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -52,8 +52,8 @@ class DeleteOrphanedTransactions extends Command
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @throws Exception
|
||||
* @return int
|
||||
* @throws Exception
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
@@ -66,45 +66,6 @@ class DeleteOrphanedTransactions extends Command
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function deleteFromOrphanedAccounts(): void
|
||||
{
|
||||
$set
|
||||
= Transaction
|
||||
::leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id')
|
||||
->whereNotNull('accounts.deleted_at')
|
||||
->get(['transactions.*']);
|
||||
$count = 0;
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($set as $transaction) {
|
||||
// delete journals
|
||||
$journal = TransactionJournal::find((int) $transaction->transaction_journal_id);
|
||||
if ($journal) {
|
||||
try {
|
||||
$journal->delete();
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (Exception $e) {
|
||||
Log::info(sprintf('Could not delete journal %s', $e->getMessage()));
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
Transaction::where('transaction_journal_id', (int) $transaction->transaction_journal_id)->delete();
|
||||
$this->line(
|
||||
sprintf(
|
||||
'Deleted transaction journal #%d because account #%d was already deleted.',
|
||||
$transaction->transaction_journal_id,
|
||||
$transaction->account_id
|
||||
)
|
||||
);
|
||||
$count++;
|
||||
}
|
||||
if (0 === $count) {
|
||||
$this->info('No orphaned accounts.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
@@ -124,7 +85,7 @@ class DeleteOrphanedTransactions extends Command
|
||||
);
|
||||
/** @var stdClass $entry */
|
||||
foreach ($set as $entry) {
|
||||
$transaction = Transaction::find((int) $entry->transaction_id);
|
||||
$transaction = Transaction::find((int)$entry->transaction_id);
|
||||
$transaction->delete();
|
||||
$this->info(
|
||||
sprintf(
|
||||
@@ -139,4 +100,43 @@ class DeleteOrphanedTransactions extends Command
|
||||
$this->info('No orphaned transactions.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function deleteFromOrphanedAccounts(): void
|
||||
{
|
||||
$set
|
||||
= Transaction
|
||||
::leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id')
|
||||
->whereNotNull('accounts.deleted_at')
|
||||
->get(['transactions.*']);
|
||||
$count = 0;
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($set as $transaction) {
|
||||
// delete journals
|
||||
$journal = TransactionJournal::find((int)$transaction->transaction_journal_id);
|
||||
if ($journal) {
|
||||
try {
|
||||
$journal->delete();
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (Exception $e) {
|
||||
Log::info(sprintf('Could not delete journal %s', $e->getMessage()));
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
Transaction::where('transaction_journal_id', (int)$transaction->transaction_journal_id)->delete();
|
||||
$this->line(
|
||||
sprintf(
|
||||
'Deleted transaction journal #%d because account #%d was already deleted.',
|
||||
$transaction->transaction_journal_id,
|
||||
$transaction->account_id
|
||||
)
|
||||
);
|
||||
$count++;
|
||||
}
|
||||
if (0 === $count) {
|
||||
$this->info('No orphaned accounts.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -64,35 +64,39 @@ class EnableCurrencies extends Command
|
||||
/** @var Collection $meta */
|
||||
$meta = AccountMeta::where('name', 'currency_id')->groupBy('data')->get(['data']);
|
||||
foreach ($meta as $entry) {
|
||||
$found[] = (int) $entry->data;
|
||||
$found[] = (int)$entry->data;
|
||||
}
|
||||
|
||||
// get all from journals:
|
||||
/** @var Collection $journals */
|
||||
$journals = TransactionJournal::groupBy('transaction_currency_id')->get(['transaction_currency_id']);
|
||||
foreach ($journals as $entry) {
|
||||
$found[] = (int) $entry->transaction_currency_id;
|
||||
$found[] = (int)$entry->transaction_currency_id;
|
||||
}
|
||||
|
||||
// get all from transactions
|
||||
/** @var Collection $transactions */
|
||||
$transactions = Transaction::groupBy('transaction_currency_id', 'foreign_currency_id')->get(['transaction_currency_id','foreign_currency_id']);
|
||||
$transactions = Transaction::groupBy('transaction_currency_id', 'foreign_currency_id')->get(['transaction_currency_id', 'foreign_currency_id']);
|
||||
foreach ($transactions as $entry) {
|
||||
$found[] = (int) $entry->transaction_currency_id;
|
||||
$found[] = (int) $entry->foreign_currency_id;
|
||||
$found[] = (int)$entry->transaction_currency_id;
|
||||
$found[] = (int)$entry->foreign_currency_id;
|
||||
}
|
||||
|
||||
// get all from budget limits
|
||||
/** @var Collection $limits */
|
||||
$limits = BudgetLimit::groupBy('transaction_currency_id')->get(['transaction_currency_id']);
|
||||
foreach ($limits as $entry) {
|
||||
$found[] = (int) $entry->transaction_currency_id;
|
||||
$found[] = (int)$entry->transaction_currency_id;
|
||||
}
|
||||
|
||||
$found = array_values(array_unique($found));
|
||||
$found = array_values(array_filter($found, function (int $currencyId) {
|
||||
return $currencyId !== 0;
|
||||
}));
|
||||
$found = array_values(
|
||||
array_filter(
|
||||
$found, function (int $currencyId) {
|
||||
return $currencyId !== 0;
|
||||
}
|
||||
)
|
||||
);
|
||||
$message = sprintf('%d different currencies are currently in use.', count($found));
|
||||
$this->info($message);
|
||||
Log::debug($message, $found);
|
||||
|
@@ -39,11 +39,13 @@ class FixAccountTypes extends Command
|
||||
{
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Make sure all journals have the correct from/to account types.';
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'firefly-iii:fix-account-types';
|
||||
@@ -54,6 +56,7 @@ class FixAccountTypes extends Command
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
* @throws FireflyException
|
||||
*/
|
||||
@@ -84,11 +87,87 @@ class FixAccountTypes extends Command
|
||||
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
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function inspectJournal(TransactionJournal $journal): void
|
||||
{
|
||||
$transactions = $journal->transactions()->count();
|
||||
if (2 !== $transactions) {
|
||||
Log::debug(sprintf('Journal has %d transactions, so can\'t fix.', $transactions));
|
||||
$this->info(sprintf('Cannot inspect transaction journal #%d because it has %d transaction(s) instead of 2.', $journal->id, $transactions));
|
||||
|
||||
return;
|
||||
}
|
||||
$type = $journal->transactionType->type;
|
||||
$sourceTransaction = $this->getSourceTransaction($journal);
|
||||
$destTransaction = $this->getDestinationTransaction($journal);
|
||||
$sourceAccount = $sourceTransaction->account;
|
||||
$sourceAccountType = $sourceAccount->accountType->type;
|
||||
$destAccount = $destTransaction->account;
|
||||
$destAccountType = $destAccount->accountType->type;
|
||||
|
||||
if (!array_key_exists($type, $this->expected)) {
|
||||
// @codeCoverageIgnoreStart
|
||||
Log::info(sprintf('No source/destination info for transaction type %s.', $type));
|
||||
$this->info(sprintf('No source/destination info for transaction type %s.', $type));
|
||||
|
||||
return;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
if (!array_key_exists($sourceAccountType, $this->expected[$type])) {
|
||||
Log::debug(sprintf('Going to fix journal #%d', $journal->id));
|
||||
$this->fixJournal($journal, $type, $sourceTransaction, $destTransaction);
|
||||
|
||||
return;
|
||||
}
|
||||
$expectedTypes = $this->expected[$type][$sourceAccountType];
|
||||
if (!in_array($destAccountType, $expectedTypes, true)) {
|
||||
Log::debug(sprintf('Going to fix journal #%d', $journal->id));
|
||||
$this->fixJournal($journal, $type, $sourceTransaction, $destTransaction);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return Transaction
|
||||
*/
|
||||
private function getSourceTransaction(TransactionJournal $journal): Transaction
|
||||
{
|
||||
return $journal->transactions->firstWhere('amount', '<', 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return Transaction
|
||||
*/
|
||||
private function getDestinationTransaction(TransactionJournal $journal): Transaction
|
||||
{
|
||||
return $journal->transactions->firstWhere('amount', '>', 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param string $type
|
||||
* @param Transaction $source
|
||||
* @param Transaction $dest
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function fixJournal(TransactionJournal $journal, string $type, Transaction $source, Transaction $dest): void
|
||||
@@ -132,7 +211,10 @@ class FixAccountTypes extends Command
|
||||
$result = $this->factory->findOrCreate($dest->account->name, AccountType::EXPENSE);
|
||||
$dest->account()->associate($result);
|
||||
$dest->save();
|
||||
$message = sprintf('Transaction journal #%d, destination account changed from #%d ("%s") to #%d ("%s").', $journal->id, $oldDest->id, $oldDest->name, $result->id, $result->name);
|
||||
$message = sprintf(
|
||||
'Transaction journal #%d, destination account changed from #%d ("%s") to #%d ("%s").', $journal->id, $oldDest->id, $oldDest->name,
|
||||
$result->id, $result->name
|
||||
);
|
||||
$this->info($message);
|
||||
Log::debug($message);
|
||||
$this->inspectJournal($journal);
|
||||
@@ -145,7 +227,10 @@ class FixAccountTypes extends Command
|
||||
$oldSource = $dest->account;
|
||||
$source->account()->associate($result);
|
||||
$source->save();
|
||||
$message = sprintf('Transaction journal #%d, source account changed from #%d ("%s") to #%d ("%s").', $journal->id, $oldSource->id, $oldSource->name, $result->id, $result->name);
|
||||
$message = sprintf(
|
||||
'Transaction journal #%d, source account changed from #%d ("%s") to #%d ("%s").', $journal->id, $oldSource->id, $oldSource->name,
|
||||
$result->id, $result->name
|
||||
);
|
||||
$this->info($message);
|
||||
Log::debug($message);
|
||||
$this->inspectJournal($journal);
|
||||
@@ -163,75 +248,4 @@ class FixAccountTypes extends Command
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @return Transaction
|
||||
*/
|
||||
private function getDestinationTransaction(TransactionJournal $journal): Transaction
|
||||
{
|
||||
return $journal->transactions->firstWhere('amount', '>', 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @return Transaction
|
||||
*/
|
||||
private function getSourceTransaction(TransactionJournal $journal): Transaction
|
||||
{
|
||||
return $journal->transactions->firstWhere('amount', '<', 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function inspectJournal(TransactionJournal $journal): void
|
||||
{
|
||||
$transactions = $journal->transactions()->count();
|
||||
if (2 !== $transactions) {
|
||||
Log::debug(sprintf('Journal has %d transactions, so can\'t fix.', $transactions));
|
||||
$this->info(sprintf('Cannot inspect transaction journal #%d because it has %d transaction(s) instead of 2.', $journal->id, $transactions));
|
||||
|
||||
return;
|
||||
}
|
||||
$type = $journal->transactionType->type;
|
||||
$sourceTransaction = $this->getSourceTransaction($journal);
|
||||
$destTransaction = $this->getDestinationTransaction($journal);
|
||||
$sourceAccount = $sourceTransaction->account;
|
||||
$sourceAccountType = $sourceAccount->accountType->type;
|
||||
$destAccount = $destTransaction->account;
|
||||
$destAccountType = $destAccount->accountType->type;
|
||||
|
||||
if (!array_key_exists($type, $this->expected)) {
|
||||
// @codeCoverageIgnoreStart
|
||||
Log::info(sprintf('No source/destination info for transaction type %s.', $type));
|
||||
$this->info(sprintf('No source/destination info for transaction type %s.', $type));
|
||||
|
||||
return;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
if (!array_key_exists($sourceAccountType, $this->expected[$type])) {
|
||||
Log::debug(sprintf('Going to fix journal #%d', $journal->id));
|
||||
$this->fixJournal($journal, $type, $sourceTransaction, $destTransaction);
|
||||
|
||||
return;
|
||||
}
|
||||
$expectedTypes = $this->expected[$type][$sourceAccountType];
|
||||
if (!in_array($destAccountType, $expectedTypes, true)) {
|
||||
Log::debug(sprintf('Going to fix journal #%d', $journal->id));
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
@@ -62,12 +62,12 @@ class FixGroupAccounts extends Command
|
||||
::groupBy('transaction_group_id')
|
||||
->get(['transaction_group_id', DB::raw('COUNT(transaction_group_id) as the_count')]);
|
||||
foreach ($res as $journal) {
|
||||
if ((int) $journal->the_count > 1) {
|
||||
$groups[] = (int) $journal->transaction_group_id;
|
||||
if ((int)$journal->the_count > 1) {
|
||||
$groups[] = (int)$journal->transaction_group_id;
|
||||
}
|
||||
}
|
||||
$handler = new UpdatedGroupEventHandler;
|
||||
foreach($groups as $groupId) {
|
||||
foreach ($groups as $groupId) {
|
||||
$group = TransactionGroup::find($groupId);
|
||||
$event = new UpdatedTransactionGroup($group);
|
||||
$handler->unifyAccounts($event);
|
||||
|
@@ -69,7 +69,7 @@ class FixLongDescriptions extends Command
|
||||
$groups = TransactionGroup::get(['id', 'title']);
|
||||
/** @var TransactionGroup $group */
|
||||
foreach ($groups as $group) {
|
||||
if (strlen((string) $group->title) > self::MAX_LENGTH) {
|
||||
if (strlen((string)$group->title) > self::MAX_LENGTH) {
|
||||
$group->title = substr($group->title, 0, self::MAX_LENGTH);
|
||||
$group->save();
|
||||
$this->line(sprintf('Truncated description of transaction group #%d', $group->id));
|
||||
|
@@ -73,18 +73,6 @@ class FixRecurringTransactions extends Command
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function correctTransactions(): void
|
||||
{
|
||||
$users = $this->userRepos->all();
|
||||
/** @var User $user */
|
||||
foreach ($users as $user) {
|
||||
$this->processUser($user);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -98,6 +86,18 @@ class FixRecurringTransactions extends Command
|
||||
$this->userRepos = app(UserRepositoryInterface::class);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function correctTransactions(): void
|
||||
{
|
||||
$users = $this->userRepos->all();
|
||||
/** @var User $user */
|
||||
foreach ($users as $user) {
|
||||
$this->processUser($user);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
|
@@ -79,19 +79,6 @@ class FixTransactionTypes extends Command
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param string $expectedType
|
||||
*/
|
||||
private function changeJournal(TransactionJournal $journal, string $expectedType): void
|
||||
{
|
||||
$type = TransactionType::whereType($expectedType)->first();
|
||||
if (null !== $type) {
|
||||
$journal->transaction_type_id = $type->id;
|
||||
$journal->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect all transaction journals.
|
||||
*
|
||||
@@ -120,7 +107,7 @@ class FixTransactionTypes extends Command
|
||||
|
||||
return false;
|
||||
}
|
||||
$expectedType = (string) config(sprintf('firefly.account_to_transaction.%s.%s', $source->accountType->type, $destination->accountType->type));
|
||||
$expectedType = (string)config(sprintf('firefly.account_to_transaction.%s.%s', $source->accountType->type, $destination->accountType->type));
|
||||
if ($expectedType !== $type) {
|
||||
$this->line(sprintf('Transaction journal #%d was of type "%s" but is corrected to "%s"', $journal->id, $type, $expectedType));
|
||||
$this->changeJournal($journal, $expectedType);
|
||||
@@ -134,8 +121,37 @@ class FixTransactionTypes extends Command
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @throws FireflyException
|
||||
* @return Account
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function getSourceAccount(TransactionJournal $journal): Account
|
||||
{
|
||||
$collection = $journal->transactions->filter(
|
||||
static function (Transaction $transaction) {
|
||||
return $transaction->amount < 0;
|
||||
}
|
||||
);
|
||||
if (0 === $collection->count()) {
|
||||
throw new FireflyException(sprintf('Journal #%d has no source transaction.', $journal->id));
|
||||
}
|
||||
if (1 !== $collection->count()) {
|
||||
throw new FireflyException(sprintf('Journal #%d has multiple source transactions.', $journal->id));
|
||||
}
|
||||
/** @var Transaction $transaction */
|
||||
$transaction = $collection->first();
|
||||
$account = $transaction->account;
|
||||
if (null === $account) {
|
||||
throw new FireflyException(sprintf('Journal #%d, transaction #%d has no source account.', $journal->id, $transaction->id));
|
||||
}
|
||||
|
||||
return $account;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return Account
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function getDestinationAccount(TransactionJournal $journal): Account
|
||||
{
|
||||
@@ -162,30 +178,14 @@ class FixTransactionTypes extends Command
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @throws FireflyException
|
||||
* @return Account
|
||||
* @param string $expectedType
|
||||
*/
|
||||
private function getSourceAccount(TransactionJournal $journal): Account
|
||||
private function changeJournal(TransactionJournal $journal, string $expectedType): void
|
||||
{
|
||||
$collection = $journal->transactions->filter(
|
||||
static function (Transaction $transaction) {
|
||||
return $transaction->amount < 0;
|
||||
}
|
||||
);
|
||||
if (0 === $collection->count()) {
|
||||
throw new FireflyException(sprintf('Journal #%d has no source transaction.', $journal->id));
|
||||
$type = TransactionType::whereType($expectedType)->first();
|
||||
if (null !== $type) {
|
||||
$journal->transaction_type_id = $type->id;
|
||||
$journal->save();
|
||||
}
|
||||
if (1 !== $collection->count()) {
|
||||
throw new FireflyException(sprintf('Journal #%d has multiple source transactions.', $journal->id));
|
||||
}
|
||||
/** @var Transaction $transaction */
|
||||
$transaction = $collection->first();
|
||||
$account = $transaction->account;
|
||||
if (null === $account) {
|
||||
throw new FireflyException(sprintf('Journal #%d, transaction #%d has no source account.', $journal->id, $transaction->id));
|
||||
}
|
||||
|
||||
return $account;
|
||||
}
|
||||
}
|
||||
|
@@ -56,10 +56,10 @@ class RemoveBills extends Command
|
||||
$start = microtime(true);
|
||||
/** @var TransactionType $withdrawal */
|
||||
$withdrawal = TransactionType::where('type', TransactionType::WITHDRAWAL)->first();
|
||||
if(null === $withdrawal) {
|
||||
if (null === $withdrawal) {
|
||||
return 0;
|
||||
}
|
||||
$journals = TransactionJournal::whereNotNull('bill_id')->where('transaction_type_id', '!=', $withdrawal->id)->get();
|
||||
$journals = TransactionJournal::whereNotNull('bill_id')->where('transaction_type_id', '!=', $withdrawal->id)->get();
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($journals as $journal) {
|
||||
$this->line(sprintf('Transaction journal #%d should not be linked to bill #%d.', $journal->id, $journal->bill_id));
|
||||
|
@@ -147,108 +147,16 @@ class ExportData extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
* @param array $data
|
||||
* 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.
|
||||
*
|
||||
* @throws FireflyException
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function exportData(array $options, array $data): void
|
||||
private function stupidLaravel(): void
|
||||
{
|
||||
$date = date('Y_m_d');
|
||||
foreach ($data as $key => $content) {
|
||||
$file = sprintf('%s%s_%s.csv', $options['directory'], $date, $key);
|
||||
if (false === $options['force'] && file_exists($file)) {
|
||||
throw new FireflyException(sprintf('File "%s" exists already. Use --force to overwrite.', $file));
|
||||
}
|
||||
if (true === $options['force'] && file_exists($file)) {
|
||||
$this->warn(sprintf('File "%s" exists already but will be replaced.', $file));
|
||||
}
|
||||
// continue to write to file.
|
||||
file_put_contents($file, $content);
|
||||
$this->info(sprintf('Wrote %s-export to file "%s".', $key, $file));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function getAccountsParameter(): Collection
|
||||
{
|
||||
$final = new Collection;
|
||||
$accounts = new Collection;
|
||||
$accountList = $this->option('accounts');
|
||||
$types = [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE];
|
||||
if (null !== $accountList && '' !== (string)$accountList) {
|
||||
$accountIds = explode(',', $accountList);
|
||||
$accounts = $this->accountRepository->getAccountsById($accountIds);
|
||||
}
|
||||
if (null === $accountList) {
|
||||
$accounts = $this->accountRepository->getAccountsByType($types);
|
||||
}
|
||||
// filter accounts,
|
||||
/** @var AccountType $account */
|
||||
foreach ($accounts as $account) {
|
||||
if (in_array($account->accountType->type, $types, true)) {
|
||||
$final->push($account);
|
||||
}
|
||||
}
|
||||
if (0 === $final->count()) {
|
||||
throw new FireflyException('Ended up with zero valid accounts to export from.');
|
||||
}
|
||||
|
||||
return $final;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
*
|
||||
* @return Carbon
|
||||
* @throws Exception
|
||||
*/
|
||||
private function getDateParameter(string $field): Carbon
|
||||
{
|
||||
$date = Carbon::now()->subYear();
|
||||
$error = false;
|
||||
if (null !== $this->option($field)) {
|
||||
try {
|
||||
$date = Carbon::createFromFormat('Y-m-d', $this->option($field));
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Log::error($e->getMessage());
|
||||
$this->error(sprintf('%s date "%s" must be formatted YYYY-MM-DD. Field will be ignored.', $field, $this->option('start')));
|
||||
$error = true;
|
||||
}
|
||||
}
|
||||
if (false === $error && 'start' === $field) {
|
||||
$journal = $this->journalRepository->firstNull();
|
||||
$date = null === $journal ? Carbon::now()->subYear() : $journal->date;
|
||||
$date->startOfDay();
|
||||
}
|
||||
if (false === $error && 'end' === $field) {
|
||||
$date = today(config('app.timezone'));
|
||||
$date->endOfDay();
|
||||
}
|
||||
|
||||
// fallback
|
||||
return $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws FireflyException
|
||||
*
|
||||
*/
|
||||
private function getExportDirectory(): string
|
||||
{
|
||||
$directory = (string)$this->option('export_directory');
|
||||
if (null === $directory) {
|
||||
$directory = './';
|
||||
}
|
||||
if (!is_writable($directory)) {
|
||||
throw new FireflyException(sprintf('Directory "%s" isn\'t writeable.', $directory));
|
||||
}
|
||||
|
||||
return $directory;
|
||||
$this->journalRepository = app(JournalRepositoryInterface::class);
|
||||
$this->accountRepository = app(AccountRepositoryInterface::class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -283,16 +191,108 @@ class ExportData extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param string $field
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @return Carbon
|
||||
* @throws Exception
|
||||
*/
|
||||
private function stupidLaravel(): void
|
||||
private function getDateParameter(string $field): Carbon
|
||||
{
|
||||
$this->journalRepository = app(JournalRepositoryInterface::class);
|
||||
$this->accountRepository = app(AccountRepositoryInterface::class);
|
||||
$date = Carbon::now()->subYear();
|
||||
$error = false;
|
||||
if (null !== $this->option($field)) {
|
||||
try {
|
||||
$date = Carbon::createFromFormat('Y-m-d', $this->option($field));
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Log::error($e->getMessage());
|
||||
$this->error(sprintf('%s date "%s" must be formatted YYYY-MM-DD. Field will be ignored.', $field, $this->option('start')));
|
||||
$error = true;
|
||||
}
|
||||
}
|
||||
if (false === $error && 'start' === $field) {
|
||||
$journal = $this->journalRepository->firstNull();
|
||||
$date = null === $journal ? Carbon::now()->subYear() : $journal->date;
|
||||
$date->startOfDay();
|
||||
}
|
||||
if (false === $error && 'end' === $field) {
|
||||
$date = today(config('app.timezone'));
|
||||
$date->endOfDay();
|
||||
}
|
||||
|
||||
// fallback
|
||||
return $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function getAccountsParameter(): Collection
|
||||
{
|
||||
$final = new Collection;
|
||||
$accounts = new Collection;
|
||||
$accountList = $this->option('accounts');
|
||||
$types = [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE];
|
||||
if (null !== $accountList && '' !== (string)$accountList) {
|
||||
$accountIds = explode(',', $accountList);
|
||||
$accounts = $this->accountRepository->getAccountsById($accountIds);
|
||||
}
|
||||
if (null === $accountList) {
|
||||
$accounts = $this->accountRepository->getAccountsByType($types);
|
||||
}
|
||||
// filter accounts,
|
||||
/** @var AccountType $account */
|
||||
foreach ($accounts as $account) {
|
||||
if (in_array($account->accountType->type, $types, true)) {
|
||||
$final->push($account);
|
||||
}
|
||||
}
|
||||
if (0 === $final->count()) {
|
||||
throw new FireflyException('Ended up with zero valid accounts to export from.');
|
||||
}
|
||||
|
||||
return $final;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws FireflyException
|
||||
*
|
||||
*/
|
||||
private function getExportDirectory(): string
|
||||
{
|
||||
$directory = (string)$this->option('export_directory');
|
||||
if (null === $directory) {
|
||||
$directory = './';
|
||||
}
|
||||
if (!is_writable($directory)) {
|
||||
throw new FireflyException(sprintf('Directory "%s" isn\'t writeable.', $directory));
|
||||
}
|
||||
|
||||
return $directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
* @param array $data
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function exportData(array $options, array $data): void
|
||||
{
|
||||
$date = date('Y_m_d');
|
||||
foreach ($data as $key => $content) {
|
||||
$file = sprintf('%s%s_%s.csv', $options['directory'], $date, $key);
|
||||
if (false === $options['force'] && file_exists($file)) {
|
||||
throw new FireflyException(sprintf('File "%s" exists already. Use --force to overwrite.', $file));
|
||||
}
|
||||
if (true === $options['force'] && file_exists($file)) {
|
||||
$this->warn(sprintf('File "%s" exists already but will be replaced.', $file));
|
||||
}
|
||||
// continue to write to file.
|
||||
file_put_contents($file, $content);
|
||||
$this->info(sprintf('Wrote %s-export to file "%s".', $key, $file));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -68,51 +68,6 @@ class ReportEmptyObjects extends Command
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports on accounts with no transactions.
|
||||
*/
|
||||
private function reportAccounts(): void
|
||||
{
|
||||
$set = Account::leftJoin('transactions', 'transactions.account_id', '=', 'accounts.id')
|
||||
->leftJoin('users', 'accounts.user_id', '=', 'users.id')
|
||||
->groupBy(['accounts.id', 'accounts.encrypted', 'accounts.name', 'accounts.user_id', 'users.email'])
|
||||
->whereNull('transactions.account_id')
|
||||
->get(
|
||||
['accounts.id', 'accounts.encrypted', 'accounts.name', 'accounts.user_id', 'users.email']
|
||||
);
|
||||
|
||||
/** @var stdClass $entry */
|
||||
foreach ($set as $entry) {
|
||||
$line = 'User #%d (%s) has account #%d ("%s") which has no transactions.';
|
||||
$line = sprintf($line, $entry->user_id, $entry->email, $entry->id, $entry->name);
|
||||
$this->line($line);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports on budgets with no budget limits (which makes them pointless).
|
||||
*/
|
||||
private function reportBudgetLimits(): void
|
||||
{
|
||||
$set = Budget::leftJoin('budget_limits', 'budget_limits.budget_id', '=', 'budgets.id')
|
||||
->leftJoin('users', 'budgets.user_id', '=', 'users.id')
|
||||
->groupBy(['budgets.id', 'budgets.name', 'budgets.encrypted', 'budgets.user_id', 'users.email'])
|
||||
->whereNull('budget_limits.id')
|
||||
->get(['budgets.id', 'budgets.name', 'budgets.user_id', 'budgets.encrypted', 'users.email']);
|
||||
|
||||
/** @var Budget $entry */
|
||||
foreach ($set as $entry) {
|
||||
$line = sprintf(
|
||||
'User #%d (%s) has budget #%d ("%s") which has no budget limits.',
|
||||
$entry->user_id,
|
||||
$entry->email,
|
||||
$entry->id,
|
||||
$entry->name
|
||||
);
|
||||
$this->line($line);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Report on budgets with no transactions or journals.
|
||||
*/
|
||||
@@ -188,4 +143,49 @@ class ReportEmptyObjects extends Command
|
||||
$this->line($line);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports on accounts with no transactions.
|
||||
*/
|
||||
private function reportAccounts(): void
|
||||
{
|
||||
$set = Account::leftJoin('transactions', 'transactions.account_id', '=', 'accounts.id')
|
||||
->leftJoin('users', 'accounts.user_id', '=', 'users.id')
|
||||
->groupBy(['accounts.id', 'accounts.encrypted', 'accounts.name', 'accounts.user_id', 'users.email'])
|
||||
->whereNull('transactions.account_id')
|
||||
->get(
|
||||
['accounts.id', 'accounts.encrypted', 'accounts.name', 'accounts.user_id', 'users.email']
|
||||
);
|
||||
|
||||
/** @var stdClass $entry */
|
||||
foreach ($set as $entry) {
|
||||
$line = 'User #%d (%s) has account #%d ("%s") which has no transactions.';
|
||||
$line = sprintf($line, $entry->user_id, $entry->email, $entry->id, $entry->name);
|
||||
$this->line($line);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports on budgets with no budget limits (which makes them pointless).
|
||||
*/
|
||||
private function reportBudgetLimits(): void
|
||||
{
|
||||
$set = Budget::leftJoin('budget_limits', 'budget_limits.budget_id', '=', 'budgets.id')
|
||||
->leftJoin('users', 'budgets.user_id', '=', 'users.id')
|
||||
->groupBy(['budgets.id', 'budgets.name', 'budgets.encrypted', 'budgets.user_id', 'users.email'])
|
||||
->whereNull('budget_limits.id')
|
||||
->get(['budgets.id', 'budgets.name', 'budgets.user_id', 'budgets.encrypted', 'users.email']);
|
||||
|
||||
/** @var Budget $entry */
|
||||
foreach ($set as $entry) {
|
||||
$line = sprintf(
|
||||
'User #%d (%s) has budget #%d ("%s") which has no budget limits.',
|
||||
$entry->user_id,
|
||||
$entry->email,
|
||||
$entry->id,
|
||||
$entry->name
|
||||
);
|
||||
$this->line($line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -70,7 +70,7 @@ class ReportSum extends Command
|
||||
|
||||
/** @var User $user */
|
||||
foreach ($userRepository->all() as $user) {
|
||||
$sum = (string) $user->transactions()->sum('amount');
|
||||
$sum = (string)$user->transactions()->sum('amount');
|
||||
if (0 !== bccomp($sum, '0')) {
|
||||
$message = sprintf('Error: Transactions for user #%d (%s) are off by %s!', $user->id, $user->email, $sum);
|
||||
$this->error($message);
|
||||
|
@@ -59,38 +59,6 @@ class RestoreOAuthKeys extends Command
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function generateKeys(): void
|
||||
{
|
||||
OAuthKeys::generateKeys();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function keysInDatabase(): bool
|
||||
{
|
||||
return OAuthKeys::keysInDatabase();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function keysOnDrive(): bool
|
||||
{
|
||||
return OAuthKeys::hasKeyFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function restoreKeysFromDB(): void
|
||||
{
|
||||
OAuthKeys::restoreKeysFromDB();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@@ -122,6 +90,30 @@ class RestoreOAuthKeys extends Command
|
||||
$this->line('OAuth keys are OK');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function keysInDatabase(): bool
|
||||
{
|
||||
return OAuthKeys::keysInDatabase();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function keysOnDrive(): bool
|
||||
{
|
||||
return OAuthKeys::hasKeyFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function generateKeys(): void
|
||||
{
|
||||
OAuthKeys::generateKeys();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@@ -129,4 +121,12 @@ class RestoreOAuthKeys extends Command
|
||||
{
|
||||
OAuthKeys::storeKeysInDB();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function restoreKeysFromDB(): void
|
||||
{
|
||||
OAuthKeys::restoreKeysFromDB();
|
||||
}
|
||||
}
|
||||
|
@@ -102,6 +102,7 @@ class ApplyRules extends Command
|
||||
$result = $this->verifyInput();
|
||||
if (false === $result) {
|
||||
app('telemetry')->feature('system.command.errored', $this->signature);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -121,6 +122,7 @@ class ApplyRules extends Command
|
||||
$this->warn(' --all_rules');
|
||||
|
||||
app('telemetry')->feature('system.command.errored', $this->signature);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -132,7 +134,7 @@ class ApplyRules extends Command
|
||||
|
||||
// add the accounts as filter:
|
||||
$filterAccountList = [];
|
||||
foreach($this->accounts as $account) {
|
||||
foreach ($this->accounts as $account) {
|
||||
$filterAccountList[] = $account->id;
|
||||
}
|
||||
$list = implode(',', $filterAccountList);
|
||||
@@ -157,49 +159,6 @@ class ApplyRules extends Command
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
private function getRulesToApply(): Collection
|
||||
{
|
||||
$rulesToApply = new Collection;
|
||||
/** @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->push($rule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
|
||||
@@ -271,7 +230,7 @@ class ApplyRules extends Command
|
||||
|
||||
|
||||
foreach ($accountList as $accountId) {
|
||||
$accountId = (int) $accountId;
|
||||
$accountId = (int)$accountId;
|
||||
$account = $accountRepository->findNull($accountId);
|
||||
if (null !== $account && in_array($account->accountType->type, $this->acceptedAccounts, true)) {
|
||||
$finalList->push($account);
|
||||
@@ -289,42 +248,6 @@ class ApplyRules extends Command
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function verifyInputDates(): void
|
||||
{
|
||||
// parse start date.
|
||||
$inputStart = 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) {
|
||||
$inputStart = $first->date;
|
||||
}
|
||||
}
|
||||
if (null !== $startString && '' !== $startString) {
|
||||
$inputStart = Carbon::createFromFormat('Y-m-d', $startString);
|
||||
}
|
||||
|
||||
// parse end date
|
||||
$inputEnd = Carbon::now();
|
||||
$endString = $this->option('end_date');
|
||||
if (null !== $endString && '' !== $endString) {
|
||||
$inputEnd = Carbon::createFromFormat('Y-m-d', $endString);
|
||||
}
|
||||
|
||||
if ($inputStart > $inputEnd) {
|
||||
[$inputEnd, $inputStart] = [$inputStart, $inputEnd];
|
||||
}
|
||||
|
||||
$this->startDate = $inputStart;
|
||||
$this->endDate = $inputEnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
@@ -343,7 +266,7 @@ class ApplyRules extends Command
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
foreach ($ruleGroupList as $ruleGroupId) {
|
||||
$ruleGroup = $this->ruleGroupRepository->find((int) $ruleGroupId);
|
||||
$ruleGroup = $this->ruleGroupRepository->find((int)$ruleGroupId);
|
||||
if ($ruleGroup->active) {
|
||||
$this->ruleGroupSelection[] = $ruleGroup->id;
|
||||
}
|
||||
@@ -376,7 +299,7 @@ class ApplyRules extends Command
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
foreach ($ruleList as $ruleId) {
|
||||
$rule = $this->ruleRepository->find((int) $ruleId);
|
||||
$rule = $this->ruleRepository->find((int)$ruleId);
|
||||
if (null !== $rule && $rule->active) {
|
||||
$this->ruleSelection[] = $rule->id;
|
||||
}
|
||||
@@ -384,4 +307,83 @@ class ApplyRules extends Command
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function verifyInputDates(): void
|
||||
{
|
||||
// parse start date.
|
||||
$inputStart = 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) {
|
||||
$inputStart = $first->date;
|
||||
}
|
||||
}
|
||||
if (null !== $startString && '' !== $startString) {
|
||||
$inputStart = Carbon::createFromFormat('Y-m-d', $startString);
|
||||
}
|
||||
|
||||
// parse end date
|
||||
$inputEnd = Carbon::now();
|
||||
$endString = $this->option('end_date');
|
||||
if (null !== $endString && '' !== $endString) {
|
||||
$inputEnd = Carbon::createFromFormat('Y-m-d', $endString);
|
||||
}
|
||||
|
||||
if ($inputStart > $inputEnd) {
|
||||
[$inputEnd, $inputStart] = [$inputStart, $inputEnd];
|
||||
}
|
||||
|
||||
$this->startDate = $inputStart;
|
||||
$this->endDate = $inputEnd;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
private function grabAllRules(): void
|
||||
{
|
||||
$this->groups = $this->ruleGroupRepository->getActiveGroups();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
private function getRulesToApply(): Collection
|
||||
{
|
||||
$rulesToApply = new Collection;
|
||||
/** @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->push($rule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $rulesToApply;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
@@ -66,11 +66,11 @@ class Cron extends Command
|
||||
$date = null;
|
||||
try {
|
||||
$date = new Carbon($this->option('date'));
|
||||
} catch (InvalidArgumentException|Exception $e) {
|
||||
} catch (InvalidArgumentException | Exception $e) {
|
||||
$this->error(sprintf('"%s" is not a valid date', $this->option('date')));
|
||||
$e->getMessage();
|
||||
}
|
||||
$force = (bool) $this->option('force');
|
||||
$force = (bool)$this->option('force');
|
||||
|
||||
/*
|
||||
* Fire recurring transaction cron job.
|
||||
@@ -108,9 +108,36 @@ class Cron extends Command
|
||||
$this->info('More feedback on the cron jobs can be found in the log files.');
|
||||
|
||||
app('telemetry')->feature('system.command.executed', $this->signature);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $force
|
||||
* @param Carbon|null $date
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function recurringCronJob(bool $force, ?Carbon $date): void
|
||||
{
|
||||
$recurring = new RecurringCronjob;
|
||||
$recurring->setForce($force);
|
||||
|
||||
// set date in cron job:
|
||||
if (null !== $date) {
|
||||
$recurring->setDate($date);
|
||||
}
|
||||
|
||||
$result = $recurring->fire();
|
||||
|
||||
if (false === $result) {
|
||||
$this->line('The recurring transaction cron job did not fire.');
|
||||
}
|
||||
if (true === $result) {
|
||||
$this->line('The recurring transaction cron job fired successfully.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $force
|
||||
* @param Carbon|null $date
|
||||
@@ -138,32 +165,6 @@ class Cron extends Command
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $force
|
||||
* @param Carbon|null $date
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function recurringCronJob(bool $force, ?Carbon $date): void
|
||||
{
|
||||
$recurring = new RecurringCronjob;
|
||||
$recurring->setForce($force);
|
||||
|
||||
// set date in cron job:
|
||||
if (null !== $date) {
|
||||
$recurring->setDate($date);
|
||||
}
|
||||
|
||||
$result = $recurring->fire();
|
||||
|
||||
if (false === $result) {
|
||||
$this->line('The recurring transaction cron job did not fire.');
|
||||
}
|
||||
if (true === $result) {
|
||||
$this->line('The recurring transaction cron job fired successfully.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $force
|
||||
* @param Carbon|null $date
|
||||
|
@@ -92,27 +92,6 @@ class AccountCurrencies extends Command
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
@@ -127,6 +106,66 @@ class AccountCurrencies extends Command
|
||||
$this->count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 updateAccountCurrencies(): void
|
||||
{
|
||||
Log::debug('Now in updateAccountCurrencies()');
|
||||
$users = $this->userRepos->all();
|
||||
$defaultCurrencyCode = (string)config('firefly.default_currency', 'EUR');
|
||||
Log::debug(sprintf('Default currency is %s', $defaultCurrencyCode));
|
||||
foreach ($users as $user) {
|
||||
$this->updateCurrenciesForUser($user, $defaultCurrencyCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param string $systemCurrencyCode
|
||||
*/
|
||||
private function updateCurrenciesForUser(User $user, string $systemCurrencyCode): void
|
||||
{
|
||||
Log::debug(sprintf('Now in updateCurrenciesForUser(%s, %s)', $user->email, $systemCurrencyCode));
|
||||
$this->accountRepos->setUser($user);
|
||||
$accounts = $this->accountRepos->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
|
||||
|
||||
// get user's currency preference:
|
||||
$defaultCurrencyCode = app('preferences')->getForUser($user, 'currencyPreference', $systemCurrencyCode)->data;
|
||||
if (!is_string($defaultCurrencyCode)) {
|
||||
$defaultCurrencyCode = $systemCurrencyCode;
|
||||
}
|
||||
Log::debug(sprintf('Users currency pref is %s', $defaultCurrencyCode));
|
||||
|
||||
/** @var TransactionCurrency $defaultCurrency */
|
||||
$defaultCurrency = TransactionCurrency::where('code', $defaultCurrencyCode)->first();
|
||||
|
||||
if (null === $defaultCurrency) {
|
||||
Log::error(sprintf('Users currency pref "%s" does not exist!', $defaultCurrencyCode));
|
||||
$this->error(sprintf('User has a preference for "%s", but this currency does not exist.', $defaultCurrencyCode));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
$this->updateAccount($account, $defaultCurrency);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param TransactionCurrency $currency
|
||||
@@ -136,13 +175,13 @@ class AccountCurrencies extends Command
|
||||
Log::debug(sprintf('Now in updateAccount(%d, %s)', $account->id, $currency->code));
|
||||
$this->accountRepos->setUser($account->user);
|
||||
|
||||
$accountCurrency = (int) $this->accountRepos->getMetaValue($account, 'currency_id');
|
||||
$accountCurrency = (int)$this->accountRepos->getMetaValue($account, 'currency_id');
|
||||
Log::debug(sprintf('Account currency is #%d', $accountCurrency));
|
||||
|
||||
$openingBalance = $this->accountRepos->getOpeningBalance($account);
|
||||
$obCurrency = 0;
|
||||
if (null !== $openingBalance) {
|
||||
$obCurrency = (int) $openingBalance->transaction_currency_id;
|
||||
$obCurrency = (int)$openingBalance->transaction_currency_id;
|
||||
Log::debug('Account has opening balance.');
|
||||
}
|
||||
Log::debug(sprintf('Account OB currency is #%d.', $obCurrency));
|
||||
@@ -192,47 +231,8 @@ class AccountCurrencies extends Command
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function updateAccountCurrencies(): void
|
||||
private function markAsExecuted(): void
|
||||
{
|
||||
Log::debug('Now in updateAccountCurrencies()');
|
||||
$users = $this->userRepos->all();
|
||||
$defaultCurrencyCode = (string) config('firefly.default_currency', 'EUR');
|
||||
Log::debug(sprintf('Default currency is %s', $defaultCurrencyCode));
|
||||
foreach ($users as $user) {
|
||||
$this->updateCurrenciesForUser($user, $defaultCurrencyCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param string $systemCurrencyCode
|
||||
*/
|
||||
private function updateCurrenciesForUser(User $user, string $systemCurrencyCode): void
|
||||
{
|
||||
Log::debug(sprintf('Now in updateCurrenciesForUser(%s, %s)', $user->email, $systemCurrencyCode));
|
||||
$this->accountRepos->setUser($user);
|
||||
$accounts = $this->accountRepos->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
|
||||
|
||||
// get user's currency preference:
|
||||
$defaultCurrencyCode = app('preferences')->getForUser($user, 'currencyPreference', $systemCurrencyCode)->data;
|
||||
if (!is_string($defaultCurrencyCode)) {
|
||||
$defaultCurrencyCode = $systemCurrencyCode;
|
||||
}
|
||||
Log::debug(sprintf('Users currency pref is %s', $defaultCurrencyCode));
|
||||
|
||||
/** @var TransactionCurrency $defaultCurrency */
|
||||
$defaultCurrency = TransactionCurrency::where('code', $defaultCurrencyCode)->first();
|
||||
|
||||
if (null === $defaultCurrency) {
|
||||
Log::error(sprintf('Users currency pref "%s" does not exist!', $defaultCurrencyCode));
|
||||
$this->error(sprintf('User has a preference for "%s", but this currency does not exist.', $defaultCurrencyCode));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
$this->updateAccount($account, $defaultCurrency);
|
||||
}
|
||||
app('fireflyconfig')->set(self::CONFIG_NAME, true);
|
||||
}
|
||||
}
|
||||
|
@@ -79,7 +79,7 @@ class AppendBudgetLimitPeriods extends Command
|
||||
|
||||
$this->theresNoLimit();
|
||||
|
||||
$this->markAsExecuted();
|
||||
$this->markAsExecuted();
|
||||
|
||||
$end = round(microtime(true) - $start, 2);
|
||||
$this->info(sprintf('Fixed budget limits in %s seconds.', $end));
|
||||
@@ -100,6 +100,44 @@ class AppendBudgetLimitPeriods extends Command
|
||||
return false; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function theresNoLimit(): void
|
||||
{
|
||||
$limits = BudgetLimit::whereNull('period')->get();
|
||||
/** @var BudgetLimit $limit */
|
||||
foreach ($limits as $limit) {
|
||||
$this->fixLimit($limit);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BudgetLimit $limit
|
||||
*/
|
||||
private function fixLimit(BudgetLimit $limit)
|
||||
{
|
||||
$period = $this->getLimitPeriod($limit);
|
||||
|
||||
if (null === $period) {
|
||||
$message = sprintf(
|
||||
'Could not guesstimate budget limit #%d (%s - %s) period.', $limit->id, $limit->start_date->format('Y-m-d'), $limit->end_date->format('Y-m-d')
|
||||
);
|
||||
$this->warn($message);
|
||||
Log::warning($message);
|
||||
|
||||
return;
|
||||
}
|
||||
$limit->period = $period;
|
||||
$limit->save();
|
||||
|
||||
$msg = sprintf(
|
||||
'Budget limit #%d (%s - %s) period is "%s".', $limit->id, $limit->start_date->format('Y-m-d'), $limit->end_date->format('Y-m-d'), $period
|
||||
);
|
||||
Log::debug($msg);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BudgetLimit $limit
|
||||
*
|
||||
@@ -160,37 +198,4 @@ class AppendBudgetLimitPeriods extends Command
|
||||
{
|
||||
app('fireflyconfig')->set(self::CONFIG_NAME, true);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function theresNoLimit(): void
|
||||
{
|
||||
$limits = BudgetLimit::whereNull('period')->get();
|
||||
/** @var BudgetLimit $limit */
|
||||
foreach ($limits as $limit) {
|
||||
$this->fixLimit($limit);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BudgetLimit $limit
|
||||
*/
|
||||
private function fixLimit(BudgetLimit $limit)
|
||||
{
|
||||
$period = $this->getLimitPeriod($limit);
|
||||
|
||||
if (null === $period) {
|
||||
$message = sprintf('Could not guesstimate budget limit #%d (%s - %s) period.', $limit->id, $limit->start_date->format('Y-m-d'), $limit->end_date->format('Y-m-d'));
|
||||
$this->warn($message);
|
||||
Log::warning($message);
|
||||
return;
|
||||
}
|
||||
$limit->period = $period;
|
||||
$limit->save();
|
||||
|
||||
$msg = sprintf('Budget limit #%d (%s - %s) period is "%s".', $limit->id, $limit->start_date->format('Y-m-d'), $limit->end_date->format('Y-m-d'), $period);
|
||||
Log::debug($msg);
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -83,43 +83,16 @@ class BackToJournals extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @return bool
|
||||
*/
|
||||
private function getIdsForBudgets(): array
|
||||
private function isMigrated(): bool
|
||||
{
|
||||
$transactions = DB::table('budget_transaction')->distinct()->get(['transaction_id'])->pluck('transaction_id')->toArray();
|
||||
$array = [];
|
||||
$chunks = array_chunk($transactions, 500);
|
||||
|
||||
foreach ($chunks as $chunk) {
|
||||
$set = DB::table('transactions')
|
||||
->whereIn('transactions.id', $chunk)
|
||||
->get(['transaction_journal_id'])->pluck('transaction_journal_id')->toArray();
|
||||
/** @noinspection SlowArrayOperationsInLoopInspection */
|
||||
$array = array_merge($array, $set);
|
||||
$configVar = app('fireflyconfig')->get(MigrateToGroups::CONFIG_NAME, false);
|
||||
if (null !== $configVar) {
|
||||
return (bool)$configVar->data;
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getIdsForCategories(): array
|
||||
{
|
||||
$transactions = DB::table('category_transaction')->distinct()->get(['transaction_id'])->pluck('transaction_id')->toArray();
|
||||
$array = [];
|
||||
$chunks = array_chunk($transactions, 500);
|
||||
|
||||
foreach ($chunks as $chunk) {
|
||||
$set = DB::table('transactions')
|
||||
->whereIn('transactions.id', $chunk)
|
||||
->get(['transaction_journal_id'])->pluck('transaction_journal_id')->toArray();
|
||||
/** @noinspection SlowArrayOperationsInLoopInspection */
|
||||
$array = array_merge($array, $set);
|
||||
}
|
||||
|
||||
return $array;
|
||||
return false; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,33 +102,12 @@ class BackToJournals extends Command
|
||||
{
|
||||
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||
if (null !== $configVar) {
|
||||
return (bool) $configVar->data;
|
||||
return (bool)$configVar->data;
|
||||
}
|
||||
|
||||
return false; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function isMigrated(): bool
|
||||
{
|
||||
$configVar = app('fireflyconfig')->get(MigrateToGroups::CONFIG_NAME, false);
|
||||
if (null !== $configVar) {
|
||||
return (bool) $configVar->data;
|
||||
}
|
||||
|
||||
return false; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function markAsExecuted(): void
|
||||
{
|
||||
app('fireflyconfig')->set(self::CONFIG_NAME, true);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@@ -189,6 +141,26 @@ class BackToJournals extends Command
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getIdsForBudgets(): array
|
||||
{
|
||||
$transactions = DB::table('budget_transaction')->distinct()->get(['transaction_id'])->pluck('transaction_id')->toArray();
|
||||
$array = [];
|
||||
$chunks = array_chunk($transactions, 500);
|
||||
|
||||
foreach ($chunks as $chunk) {
|
||||
$set = DB::table('transactions')
|
||||
->whereIn('transactions.id', $chunk)
|
||||
->get(['transaction_journal_id'])->pluck('transaction_journal_id')->toArray();
|
||||
/** @noinspection SlowArrayOperationsInLoopInspection */
|
||||
$array = array_merge($array, $set);
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
*/
|
||||
@@ -213,7 +185,7 @@ class BackToJournals extends Command
|
||||
// both have a budget, but they don't match.
|
||||
if (null !== $budget && null !== $journalBudget && $budget->id !== $journalBudget->id) {
|
||||
// sync to journal:
|
||||
$journal->budgets()->sync([(int) $budget->id]);
|
||||
$journal->budgets()->sync([(int)$budget->id]);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -221,7 +193,7 @@ class BackToJournals extends Command
|
||||
// transaction has a budget, but the journal doesn't.
|
||||
if (null !== $budget && null === $journalBudget) {
|
||||
// sync to journal:
|
||||
$journal->budgets()->sync([(int) $budget->id]);
|
||||
$journal->budgets()->sync([(int)$budget->id]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,6 +221,26 @@ class BackToJournals extends Command
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getIdsForCategories(): array
|
||||
{
|
||||
$transactions = DB::table('category_transaction')->distinct()->get(['transaction_id'])->pluck('transaction_id')->toArray();
|
||||
$array = [];
|
||||
$chunks = array_chunk($transactions, 500);
|
||||
|
||||
foreach ($chunks as $chunk) {
|
||||
$set = DB::table('transactions')
|
||||
->whereIn('transactions.id', $chunk)
|
||||
->get(['transaction_journal_id'])->pluck('transaction_journal_id')->toArray();
|
||||
/** @noinspection SlowArrayOperationsInLoopInspection */
|
||||
$array = array_merge($array, $set);
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
*/
|
||||
@@ -272,12 +264,20 @@ class BackToJournals extends Command
|
||||
// both have a category, but they don't match.
|
||||
if (null !== $category && null !== $journalCategory && $category->id !== $journalCategory->id) {
|
||||
// sync to journal:
|
||||
$journal->categories()->sync([(int) $category->id]);
|
||||
$journal->categories()->sync([(int)$category->id]);
|
||||
}
|
||||
|
||||
// transaction has a category, but the journal doesn't.
|
||||
if (null !== $category && null === $journalCategory) {
|
||||
$journal->categories()->sync([(int) $category->id]);
|
||||
$journal->categories()->sync([(int)$category->id]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function markAsExecuted(): void
|
||||
{
|
||||
app('fireflyconfig')->set(self::CONFIG_NAME, true);
|
||||
}
|
||||
}
|
||||
|
@@ -103,7 +103,7 @@ class BudgetLimitCurrency extends Command
|
||||
{
|
||||
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||
if (null !== $configVar) {
|
||||
return (bool) $configVar->data;
|
||||
return (bool)$configVar->data;
|
||||
}
|
||||
|
||||
return false; // @codeCoverageIgnore
|
||||
|
@@ -102,7 +102,7 @@ class CCLiabilities extends Command
|
||||
{
|
||||
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||
if (null !== $configVar) {
|
||||
return (bool) $configVar->data;
|
||||
return (bool)$configVar->data;
|
||||
}
|
||||
|
||||
return false; // @codeCoverageIgnore
|
||||
|
@@ -72,7 +72,7 @@ class MigrateAttachments extends Command
|
||||
foreach ($attachments as $att) {
|
||||
|
||||
// move description:
|
||||
$attDescription = (string) $att->description;
|
||||
$attDescription = (string)$att->description;
|
||||
if ('' !== $attDescription) {
|
||||
|
||||
// find or create note:
|
||||
@@ -112,7 +112,7 @@ class MigrateAttachments extends Command
|
||||
{
|
||||
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||
if (null !== $configVar) {
|
||||
return (bool) $configVar->data;
|
||||
return (bool)$configVar->data;
|
||||
}
|
||||
|
||||
return false; // @codeCoverageIgnore
|
||||
|
@@ -111,7 +111,7 @@ class MigrateJournalNotes extends Command
|
||||
{
|
||||
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||
if (null !== $configVar) {
|
||||
return (bool) $configVar->data;
|
||||
return (bool)$configVar->data;
|
||||
}
|
||||
|
||||
return false; // @codeCoverageIgnore
|
||||
|
@@ -85,19 +85,26 @@ class MigrateRecurrenceMeta extends Command
|
||||
{
|
||||
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||
if (null !== $configVar) {
|
||||
return (bool) $configVar->data;
|
||||
return (bool)$configVar->data;
|
||||
}
|
||||
|
||||
return false; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function markAsExecuted(): void
|
||||
private function migrateMetaData(): int
|
||||
{
|
||||
app('fireflyconfig')->set(self::CONFIG_NAME, true);
|
||||
$count = 0;
|
||||
// get all recurrence meta data:
|
||||
$collection = RecurrenceMeta::with('recurrence')->get();
|
||||
/** @var RecurrenceMeta $meta */
|
||||
foreach ($collection as $meta) {
|
||||
$count += $this->migrateEntry($meta);
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,18 +142,10 @@ class MigrateRecurrenceMeta extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*
|
||||
*/
|
||||
private function migrateMetaData(): int
|
||||
private function markAsExecuted(): void
|
||||
{
|
||||
$count = 0;
|
||||
// get all recurrence meta data:
|
||||
$collection = RecurrenceMeta::with('recurrence')->get();
|
||||
/** @var RecurrenceMeta $meta */
|
||||
foreach ($collection as $meta) {
|
||||
$count += $this->migrateEntry($meta);
|
||||
}
|
||||
|
||||
return $count;
|
||||
app('fireflyconfig')->set(self::CONFIG_NAME, true);
|
||||
}
|
||||
}
|
||||
|
109
app/Console/Commands/Upgrade/MigrateRecurrenceType.php
Normal file
109
app/Console/Commands/Upgrade/MigrateRecurrenceType.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Console\Commands\Upgrade;
|
||||
|
||||
use FireflyIII\Models\Recurrence;
|
||||
use FireflyIII\Models\RecurrenceTransaction;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
/**
|
||||
* Class MigrateRecurrenceType
|
||||
*/
|
||||
class MigrateRecurrenceType extends Command
|
||||
{
|
||||
public const CONFIG_NAME = '550_migrate_recurrence_type';
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Migrate transaction type of recurring transaction.';
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'firefly-iii:migrate-recurrence-type {--F|force : Force the execution of this command.}';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
$start = microtime(true);
|
||||
if ($this->isExecuted() && true !== $this->option('force')) {
|
||||
$this->warn('This command has already been executed.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->migrateTypes();
|
||||
|
||||
//$this->markAsExecuted();
|
||||
|
||||
$end = round(microtime(true) - $start, 2);
|
||||
$this->info(sprintf('Update recurring transaction types in %s seconds.', $end));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 getInvalidType(): TransactionType
|
||||
{
|
||||
return TransactionType::whereType(TransactionType::INVALID)->firstOrCreate(['type' => TransactionType::INVALID]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function migrateTypes(): void
|
||||
{
|
||||
$set = Recurrence::get();
|
||||
/** @var Recurrence $recurrence */
|
||||
foreach ($set as $recurrence) {
|
||||
if ($recurrence->transactionType->type !== TransactionType::INVALID) {
|
||||
$this->migrateRecurrence($recurrence);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function markAsExecuted(): void
|
||||
{
|
||||
app('fireflyconfig')->set(self::CONFIG_NAME, true);
|
||||
}
|
||||
|
||||
private function migrateRecurrence(Recurrence $recurrence): void
|
||||
{
|
||||
$originalType = (int)$recurrence->transaction_type_id;
|
||||
$newType = $this->getInvalidType();
|
||||
$recurrence->transaction_type_id = $newType->id;
|
||||
$recurrence->save();
|
||||
/** @var RecurrenceTransaction $transaction */
|
||||
foreach ($recurrence->recurrenceTransactions as $transaction) {
|
||||
$transaction->transaction_type_id = $originalType;
|
||||
$transaction->save();
|
||||
}
|
||||
$this->line(sprintf('Updated recurrence #%d to new transaction type model.', $recurrence->id));
|
||||
}
|
||||
}
|
@@ -71,6 +71,30 @@ class MigrateTagLocations extends Command
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 migrateTagLocations(): void
|
||||
{
|
||||
$tags = Tag::get();
|
||||
/** @var Tag $tag */
|
||||
foreach ($tags as $tag) {
|
||||
if ($this->hasLocationDetails($tag)) {
|
||||
$this->migrateLocationDetails($tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
*
|
||||
@@ -81,28 +105,6 @@ class MigrateTagLocations extends Command
|
||||
return null !== $tag->latitude && null !== $tag->longitude && null !== $tag->zoomLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 Tag $tag
|
||||
*/
|
||||
@@ -121,15 +123,12 @@ class MigrateTagLocations extends Command
|
||||
$tag->save();
|
||||
}
|
||||
|
||||
private function migrateTagLocations(): void
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function markAsExecuted(): void
|
||||
{
|
||||
$tags = Tag::get();
|
||||
/** @var Tag $tag */
|
||||
foreach ($tags as $tag) {
|
||||
if ($this->hasLocationDetails($tag)) {
|
||||
$this->migrateLocationDetails($tag);
|
||||
}
|
||||
}
|
||||
app('fireflyconfig')->set(self::CONFIG_NAME, true);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -112,122 +112,19 @@ class MigrateToGroups extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param Transaction $transaction
|
||||
* 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.
|
||||
*
|
||||
* @return Transaction|null
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function findOpposingTransaction(TransactionJournal $journal, Transaction $transaction): ?Transaction
|
||||
private function stupidLaravel(): void
|
||||
{
|
||||
$set = $journal->transactions->filter(
|
||||
static function (Transaction $subject) use ($transaction) {
|
||||
$amount = (float) $transaction->amount * -1 === (float) $subject->amount;
|
||||
$identifier = $transaction->identifier === $subject->identifier;
|
||||
Log::debug(sprintf('Amount the same? %s', var_export($amount, true)));
|
||||
Log::debug(sprintf('ID the same? %s', var_export($identifier, true)));
|
||||
|
||||
return $amount && $identifier;
|
||||
}
|
||||
);
|
||||
|
||||
return $set->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
private function getDestinationTransactions(TransactionJournal $journal): Collection
|
||||
{
|
||||
return $journal->transactions->filter(
|
||||
static function (Transaction $transaction) {
|
||||
return $transaction->amount > 0;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
private function giveGroup(array $array): void
|
||||
{
|
||||
$groupId = DB::table('transaction_groups')->insertGetId(
|
||||
[
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
'title' => null,
|
||||
'user_id' => $array['user_id'],
|
||||
]
|
||||
);
|
||||
DB::table('transaction_journals')->where('id', $array['id'])->update(['transaction_group_id' => $groupId]);
|
||||
$this->count++;
|
||||
$this->count = 0;
|
||||
$this->journalRepository = app(JournalRepositoryInterface::class);
|
||||
$this->service = app(JournalDestroyService::class);
|
||||
$this->groupFactory = app(TransactionGroupFactory::class);
|
||||
$this->cliRepository = app(JournalCLIRepositoryInterface::class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -237,32 +134,12 @@ class MigrateToGroups extends Command
|
||||
{
|
||||
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||
if (null !== $configVar) {
|
||||
return (bool) $configVar->data;
|
||||
return (bool)$configVar->data;
|
||||
}
|
||||
|
||||
return false; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives all journals without a group a group.
|
||||
*/
|
||||
private function makeGroupsFromAll(): void
|
||||
{
|
||||
$orphanedJournals = $this->cliRepository->getJournalsWithoutGroup();
|
||||
$total = count($orphanedJournals);
|
||||
if ($total > 0) {
|
||||
Log::debug(sprintf('Going to convert %d transaction journals. Please hold..', $total));
|
||||
$this->line(sprintf('Going to convert %d transaction journals. Please hold..', $total));
|
||||
/** @var array $journal */
|
||||
foreach ($orphanedJournals as $array) {
|
||||
$this->giveGroup($array);
|
||||
}
|
||||
}
|
||||
if (0 === $total) {
|
||||
$this->info('No need to convert transaction journals.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
@@ -427,6 +304,145 @@ class MigrateToGroups extends Command
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
private function getDestinationTransactions(TransactionJournal $journal): Collection
|
||||
{
|
||||
return $journal->transactions->filter(
|
||||
static function (Transaction $transaction) {
|
||||
return $transaction->amount > 0;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param Transaction $transaction
|
||||
*
|
||||
* @return Transaction|null
|
||||
*/
|
||||
private function findOpposingTransaction(TransactionJournal $journal, Transaction $transaction): ?Transaction
|
||||
{
|
||||
$set = $journal->transactions->filter(
|
||||
static function (Transaction $subject) use ($transaction) {
|
||||
$amount = (float)$transaction->amount * -1 === (float)$subject->amount;
|
||||
$identifier = $transaction->identifier === $subject->identifier;
|
||||
Log::debug(sprintf('Amount the same? %s', var_export($amount, true)));
|
||||
Log::debug(sprintf('ID the same? %s', var_export($identifier, true)));
|
||||
|
||||
return $amount && $identifier;
|
||||
}
|
||||
);
|
||||
|
||||
return $set->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives all journals without a group a group.
|
||||
*/
|
||||
private function makeGroupsFromAll(): void
|
||||
{
|
||||
$orphanedJournals = $this->cliRepository->getJournalsWithoutGroup();
|
||||
$total = count($orphanedJournals);
|
||||
if ($total > 0) {
|
||||
Log::debug(sprintf('Going to convert %d transaction journals. Please hold..', $total));
|
||||
$this->line(sprintf('Going to convert %d transaction journals. Please hold..', $total));
|
||||
/** @var array $journal */
|
||||
foreach ($orphanedJournals as $array) {
|
||||
$this->giveGroup($array);
|
||||
}
|
||||
}
|
||||
if (0 === $total) {
|
||||
$this->info('No need to convert transaction journals.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $array
|
||||
*/
|
||||
private function giveGroup(array $array): void
|
||||
{
|
||||
$groupId = DB::table('transaction_groups')->insertGetId(
|
||||
[
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
'title' => null,
|
||||
'user_id' => $array['user_id'],
|
||||
]
|
||||
);
|
||||
DB::table('transaction_journals')->where('id', $array['id'])->update(['transaction_group_id' => $groupId]);
|
||||
$this->count++;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@@ -434,20 +450,4 @@ class MigrateToGroups extends Command
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@@ -67,8 +67,8 @@ class MigrateToRules extends Command
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @throws FireflyException
|
||||
* @return int
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
@@ -103,6 +103,22 @@ class MigrateToRules extends Command
|
||||
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
|
||||
*/
|
||||
@@ -110,18 +126,46 @@ class MigrateToRules extends Command
|
||||
{
|
||||
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||
if (null !== $configVar) {
|
||||
return (bool) $configVar->data;
|
||||
return (bool)$configVar->data;
|
||||
}
|
||||
|
||||
return false; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate bills to new rule structure for a specific user.
|
||||
*
|
||||
* @param User $user
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function markAsExecuted(): void
|
||||
private function migrateUser(User $user): void
|
||||
{
|
||||
app('fireflyconfig')->set(self::CONFIG_NAME, true);
|
||||
$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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,8 +186,8 @@ class MigrateToRules extends Command
|
||||
'active' => true,
|
||||
'strict' => false,
|
||||
'stop_processing' => false, // field is no longer used.
|
||||
'title' => (string) trans('firefly.rule_for_bill_title', ['name' => $bill->name], $language->data),
|
||||
'description' => (string) trans('firefly.rule_for_bill_description', ['name' => $bill->name], $language->data),
|
||||
'title' => (string)trans('firefly.rule_for_bill_title', ['name' => $bill->name], $language->data),
|
||||
'description' => (string)trans('firefly.rule_for_bill_description', ['name' => $bill->name], $language->data),
|
||||
'trigger' => 'store-journal',
|
||||
'triggers' => [
|
||||
[
|
||||
@@ -196,54 +240,10 @@ class MigrateToRules extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate bills to new rule structure for a specific user.
|
||||
*
|
||||
* @param User $user
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function migrateUser(User $user): void
|
||||
private function markAsExecuted(): 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);
|
||||
|
||||
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);
|
||||
app('fireflyconfig')->set(self::CONFIG_NAME, true);
|
||||
}
|
||||
}
|
||||
|
@@ -95,68 +95,20 @@ class OtherCurrenciesCorrections extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* 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.
|
||||
*
|
||||
* @return TransactionCurrency|null
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function getCurrency(Account $account): ?TransactionCurrency
|
||||
private function stupidLaravel(): void
|
||||
{
|
||||
$accountId = $account->id;
|
||||
if (array_key_exists($accountId, $this->accountCurrencies) && 0 === $this->accountCurrencies[$accountId]) {
|
||||
return null; // @codeCoverageIgnore
|
||||
}
|
||||
if (array_key_exists($accountId, $this->accountCurrencies) && $this->accountCurrencies[$accountId] instanceof TransactionCurrency) {
|
||||
return $this->accountCurrencies[$accountId]; // @codeCoverageIgnore
|
||||
}
|
||||
$currency = $this->accountRepos->getAccountCurrency($account);
|
||||
if (null === $currency) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$this->accountCurrencies[$accountId] = 0;
|
||||
|
||||
return null;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
$this->accountCurrencies[$accountId] = $currency;
|
||||
|
||||
return $currency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the transaction that determines the transaction that "leads" and will determine
|
||||
* the currency to be used by all transactions, and the journal itself.
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return Transaction|null
|
||||
*/
|
||||
private function getLeadTransaction(TransactionJournal $journal): ?Transaction
|
||||
{
|
||||
/** @var Transaction $lead */
|
||||
$lead = null;
|
||||
switch ($journal->transactionType->type) {
|
||||
default:
|
||||
break;
|
||||
case TransactionType::WITHDRAWAL:
|
||||
$lead = $journal->transactions()->where('amount', '<', 0)->first();
|
||||
break;
|
||||
case TransactionType::DEPOSIT:
|
||||
$lead = $journal->transactions()->where('amount', '>', 0)->first();
|
||||
break;
|
||||
case TransactionType::OPENING_BALANCE:
|
||||
// whichever isn't an initial balance account:
|
||||
$lead = $journal->transactions()->leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id')->leftJoin(
|
||||
'account_types', 'accounts.account_type_id', '=', 'account_types.id'
|
||||
)->where('account_types.type', '!=', AccountType::INITIAL_BALANCE)->first(['transactions.*']);
|
||||
break;
|
||||
case TransactionType::RECONCILIATION:
|
||||
// whichever isn't the reconciliation account:
|
||||
$lead = $journal->transactions()->leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id')->leftJoin(
|
||||
'account_types', 'accounts.account_type_id', '=', 'account_types.id'
|
||||
)->where('account_types.type', '!=', AccountType::RECONCILIATION)->first(['transactions.*']);
|
||||
break;
|
||||
}
|
||||
|
||||
return $lead;
|
||||
$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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,28 +125,21 @@ class OtherCurrenciesCorrections extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 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 markAsExecuted(): void
|
||||
private function updateOtherJournalsCurrencies(): void
|
||||
{
|
||||
app('fireflyconfig')->set(self::CONFIG_NAME, true);
|
||||
}
|
||||
$set = $this->cliRepos->getAllJournals(
|
||||
[TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::OPENING_BALANCE, TransactionType::RECONCILIATION,]
|
||||
);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($set as $journal) {
|
||||
$this->updateJournalCurrency($journal);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -256,20 +201,75 @@ class OtherCurrenciesCorrections extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Gets the transaction that determines the transaction that "leads" and will determine
|
||||
* the currency to be used by all transactions, and the journal itself.
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return Transaction|null
|
||||
*/
|
||||
private function updateOtherJournalsCurrencies(): void
|
||||
private function getLeadTransaction(TransactionJournal $journal): ?Transaction
|
||||
{
|
||||
$set = $this->cliRepos->getAllJournals(
|
||||
[TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::OPENING_BALANCE, TransactionType::RECONCILIATION,]
|
||||
);
|
||||
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($set as $journal) {
|
||||
$this->updateJournalCurrency($journal);
|
||||
/** @var Transaction $lead */
|
||||
$lead = null;
|
||||
switch ($journal->transactionType->type) {
|
||||
default:
|
||||
break;
|
||||
case TransactionType::WITHDRAWAL:
|
||||
$lead = $journal->transactions()->where('amount', '<', 0)->first();
|
||||
break;
|
||||
case TransactionType::DEPOSIT:
|
||||
$lead = $journal->transactions()->where('amount', '>', 0)->first();
|
||||
break;
|
||||
case TransactionType::OPENING_BALANCE:
|
||||
// whichever isn't an initial balance account:
|
||||
$lead = $journal->transactions()->leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id')->leftJoin(
|
||||
'account_types', 'accounts.account_type_id', '=', 'account_types.id'
|
||||
)->where('account_types.type', '!=', AccountType::INITIAL_BALANCE)->first(['transactions.*']);
|
||||
break;
|
||||
case TransactionType::RECONCILIATION:
|
||||
// whichever isn't the reconciliation account:
|
||||
$lead = $journal->transactions()->leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id')->leftJoin(
|
||||
'account_types', 'accounts.account_type_id', '=', 'account_types.id'
|
||||
)->where('account_types.type', '!=', AccountType::RECONCILIATION)->first(['transactions.*']);
|
||||
break;
|
||||
}
|
||||
|
||||
return $lead;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
* @return TransactionCurrency|null
|
||||
*/
|
||||
private function getCurrency(Account $account): ?TransactionCurrency
|
||||
{
|
||||
$accountId = $account->id;
|
||||
if (array_key_exists($accountId, $this->accountCurrencies) && 0 === $this->accountCurrencies[$accountId]) {
|
||||
return null; // @codeCoverageIgnore
|
||||
}
|
||||
if (array_key_exists($accountId, $this->accountCurrencies) && $this->accountCurrencies[$accountId] instanceof TransactionCurrency) {
|
||||
return $this->accountCurrencies[$accountId]; // @codeCoverageIgnore
|
||||
}
|
||||
$currency = $this->accountRepos->getAccountCurrency($account);
|
||||
if (null === $currency) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$this->accountCurrencies[$accountId] = 0;
|
||||
|
||||
return null;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
$this->accountCurrencies[$accountId] = $currency;
|
||||
|
||||
return $currency;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function markAsExecuted(): void
|
||||
{
|
||||
app('fireflyconfig')->set(self::CONFIG_NAME, true);
|
||||
}
|
||||
}
|
||||
|
@@ -102,7 +102,7 @@ class RenameAccountMeta extends Command
|
||||
{
|
||||
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||
if (null !== $configVar) {
|
||||
return (bool) $configVar->data;
|
||||
return (bool)$configVar->data;
|
||||
}
|
||||
|
||||
return false; // @codeCoverageIgnore
|
||||
|
@@ -105,60 +105,6 @@ class TransactionIdentifier extends Command
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
@@ -173,6 +119,19 @@ class TransactionIdentifier extends Command
|
||||
$this->count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function isExecuted(): bool
|
||||
{
|
||||
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||
if (null !== $configVar) {
|
||||
return (bool)$configVar->data;
|
||||
}
|
||||
|
||||
return false; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -202,4 +161,45 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function markAsExecuted(): void
|
||||
{
|
||||
app('fireflyconfig')->set(self::CONFIG_NAME, true);
|
||||
}
|
||||
}
|
||||
|
@@ -56,12 +56,12 @@ class TransferCurrenciesCorrections extends Command
|
||||
private JournalCLIRepositoryInterface $cliRepos;
|
||||
private int $count;
|
||||
|
||||
private ?Account $destinationAccount;
|
||||
private ?TransactionCurrency $destinationCurrency;
|
||||
private ?Transaction $destinationTransaction;
|
||||
private ?Account $sourceAccount;
|
||||
private ?TransactionCurrency $sourceCurrency;
|
||||
private ?Transaction $sourceTransaction;
|
||||
private ?Account $destinationAccount;
|
||||
private ?TransactionCurrency $destinationCurrency;
|
||||
private ?Transaction $destinationTransaction;
|
||||
private ?Account $sourceAccount;
|
||||
private ?TransactionCurrency $sourceCurrency;
|
||||
private ?Transaction $sourceTransaction;
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
@@ -99,6 +99,313 @@ class TransferCurrenciesCorrections extends Command
|
||||
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->accountRepos = app(AccountRepositoryInterface::class);
|
||||
$this->cliRepos = app(JournalCLIRepositoryInterface::class);
|
||||
$this->accountCurrencies = [];
|
||||
$this->resetInformation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all the class fields for the current transfer.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function resetInformation(): void
|
||||
{
|
||||
$this->sourceTransaction = null;
|
||||
$this->sourceAccount = null;
|
||||
$this->sourceCurrency = null;
|
||||
$this->destinationTransaction = null;
|
||||
$this->destinationAccount = null;
|
||||
$this->destinationCurrency = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function isExecuted(): bool
|
||||
{
|
||||
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||
if (null !== $configVar) {
|
||||
return (bool)$configVar->data;
|
||||
}
|
||||
|
||||
return false; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine verifies that transfers have the correct currency settings for the accounts they are linked to.
|
||||
* For transfers, this is can be a destructive routine since we FORCE them into a currency setting whether they
|
||||
* like it or not. Previous routines MUST have set the currency setting for both accounts for this to work.
|
||||
*
|
||||
* Both source and destination must match the respective currency preference. So FF3 must verify ALL
|
||||
* transactions.
|
||||
*/
|
||||
private function startUpdateRoutine(): void
|
||||
{
|
||||
$set = $this->cliRepos->getAllJournals([TransactionType::TRANSFER]);
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($set as $journal) {
|
||||
$this->updateTransferCurrency($journal);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $transfer
|
||||
*/
|
||||
private function updateTransferCurrency(TransactionJournal $transfer): void
|
||||
{
|
||||
$this->resetInformation();
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($this->isSplitJournal($transfer)) {
|
||||
$this->line(sprintf(sprintf('Transaction journal #%d is a split journal. Cannot continue.', $transfer->id)));
|
||||
|
||||
return;
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
$this->getSourceInformation($transfer);
|
||||
$this->getDestinationInformation($transfer);
|
||||
|
||||
// unexpectedly, either one is null:
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($this->isEmptyTransactions()) {
|
||||
$this->error(sprintf('Source or destination information for transaction journal #%d is null. Cannot fix this one.', $transfer->id));
|
||||
|
||||
return;
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
|
||||
// both accounts must have currency preference:
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($this->isNoCurrencyPresent()) {
|
||||
$this->error(
|
||||
sprintf('Source or destination accounts for transaction journal #%d have no currency information. Cannot fix this one.', $transfer->id)
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
// fix source transaction having no currency.
|
||||
$this->fixSourceNoCurrency();
|
||||
|
||||
// fix source transaction having bad currency.
|
||||
$this->fixSourceUnmatchedCurrency();
|
||||
|
||||
// fix destination transaction having no currency.
|
||||
$this->fixDestNoCurrency();
|
||||
|
||||
// fix destination transaction having bad currency.
|
||||
$this->fixDestinationUnmatchedCurrency();
|
||||
|
||||
// remove foreign currency information if not necessary.
|
||||
$this->fixInvalidForeignCurrency();
|
||||
// correct foreign currency info if necessary.
|
||||
$this->fixMismatchedForeignCurrency();
|
||||
|
||||
// restore missing foreign currency amount.
|
||||
$this->fixSourceNullForeignAmount();
|
||||
|
||||
$this->fixDestNullForeignAmount();
|
||||
|
||||
// fix journal itself:
|
||||
$this->fixTransactionJournalCurrency($transfer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a split transaction journal?
|
||||
*
|
||||
* @param TransactionJournal $transfer
|
||||
*
|
||||
* @return bool
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function isSplitJournal(TransactionJournal $transfer): bool
|
||||
{
|
||||
return $transfer->transactions->count() > 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* @return Transaction|null
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function getSourceTransaction(TransactionJournal $transfer): ?Transaction
|
||||
{
|
||||
return $transfer->transactions()->where('amount', '<', 0)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
* @return TransactionCurrency|null
|
||||
*/
|
||||
private function getCurrency(Account $account): ?TransactionCurrency
|
||||
{
|
||||
$accountId = $account->id;
|
||||
if (array_key_exists($accountId, $this->accountCurrencies) && 0 === $this->accountCurrencies[$accountId]) {
|
||||
return null; // @codeCoverageIgnore
|
||||
}
|
||||
if (array_key_exists($accountId, $this->accountCurrencies) && $this->accountCurrencies[$accountId] instanceof TransactionCurrency) {
|
||||
return $this->accountCurrencies[$accountId]; // @codeCoverageIgnore
|
||||
}
|
||||
$currency = $this->accountRepos->getAccountCurrency($account);
|
||||
if (null === $currency) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$this->accountCurrencies[$accountId] = 0;
|
||||
|
||||
return null;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
$this->accountCurrencies[$accountId] = $currency;
|
||||
|
||||
return $currency;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* @return Transaction|null
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function getDestinationTransaction(TransactionJournal $transfer): ?Transaction
|
||||
{
|
||||
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
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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 a currency. If not, it will be added by
|
||||
* taking it from the destination account's preference.
|
||||
@@ -121,26 +428,6 @@ class TransferCurrenciesCorrections extends Command
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -220,28 +507,6 @@ class TransferCurrenciesCorrections extends Command
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -263,27 +528,22 @@ class TransferCurrenciesCorrections extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* The source transaction must have the correct currency. If not, it will be set by
|
||||
* taking it from the source account's preference.
|
||||
* 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 fixSourceUnmatchedCurrency(): void
|
||||
private function fixDestNullForeignAmount(): 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);
|
||||
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++;
|
||||
$this->sourceTransaction->transaction_currency_id = (int)$this->sourceCurrency->id;
|
||||
$this->sourceTransaction->save();
|
||||
Log::debug(
|
||||
sprintf(
|
||||
'Restored foreign amount of destination transaction #%d to %s',
|
||||
$this->destinationTransaction->id,
|
||||
$this->destinationTransaction->foreign_amount
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,153 +571,6 @@ class TransferCurrenciesCorrections extends Command
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
* @return TransactionCurrency|null
|
||||
*/
|
||||
private function getCurrency(Account $account): ?TransactionCurrency
|
||||
{
|
||||
$accountId = $account->id;
|
||||
if (array_key_exists($accountId, $this->accountCurrencies) && 0 === $this->accountCurrencies[$accountId]) {
|
||||
return null; // @codeCoverageIgnore
|
||||
}
|
||||
if (array_key_exists($accountId, $this->accountCurrencies) && $this->accountCurrencies[$accountId] instanceof TransactionCurrency) {
|
||||
return $this->accountCurrencies[$accountId]; // @codeCoverageIgnore
|
||||
}
|
||||
$currency = $this->accountRepos->getAccountCurrency($account);
|
||||
if (null === $currency) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$this->accountCurrencies[$accountId] = 0;
|
||||
|
||||
return null;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
$this->accountCurrencies[$accountId] = $currency;
|
||||
|
||||
return $currency;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* @return Transaction|null
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function getDestinationTransaction(TransactionJournal $transfer): ?Transaction
|
||||
{
|
||||
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
|
||||
*
|
||||
* @return Transaction|null
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function getSourceTransaction(TransactionJournal $transfer): ?Transaction
|
||||
{
|
||||
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
|
||||
*/
|
||||
private function isExecuted(): bool
|
||||
{
|
||||
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||
if (null !== $configVar) {
|
||||
return (bool)$configVar->data;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@@ -465,117 +578,4 @@ class TransferCurrenciesCorrections extends Command
|
||||
{
|
||||
app('fireflyconfig')->set(self::CONFIG_NAME, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all the class fields for the current transfer.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function resetInformation(): void
|
||||
{
|
||||
$this->sourceTransaction = null;
|
||||
$this->sourceAccount = null;
|
||||
$this->sourceCurrency = null;
|
||||
$this->destinationTransaction = null;
|
||||
$this->destinationAccount = null;
|
||||
$this->destinationCurrency = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine verifies that transfers have the correct currency settings for the accounts they are linked to.
|
||||
* For transfers, this is can be a destructive routine since we FORCE them into a currency setting whether they
|
||||
* like it or not. Previous routines MUST have set the currency setting for both accounts for this to work.
|
||||
*
|
||||
* Both source and destination must match the respective currency preference. So FF3 must verify ALL
|
||||
* transactions.
|
||||
*/
|
||||
private function startUpdateRoutine(): void
|
||||
{
|
||||
$set = $this->cliRepos->getAllJournals([TransactionType::TRANSFER]);
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($set as $journal) {
|
||||
$this->updateTransferCurrency($journal);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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->accountRepos = app(AccountRepositoryInterface::class);
|
||||
$this->cliRepos = app(JournalCLIRepositoryInterface::class);
|
||||
$this->accountCurrencies = [];
|
||||
$this->resetInformation();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $transfer
|
||||
*/
|
||||
private function updateTransferCurrency(TransactionJournal $transfer): void
|
||||
{
|
||||
$this->resetInformation();
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($this->isSplitJournal($transfer)) {
|
||||
$this->line(sprintf(sprintf('Transaction journal #%d is a split journal. Cannot continue.', $transfer->id)));
|
||||
|
||||
return;
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
$this->getSourceInformation($transfer);
|
||||
$this->getDestinationInformation($transfer);
|
||||
|
||||
// unexpectedly, either one is null:
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($this->isEmptyTransactions()) {
|
||||
$this->error(sprintf('Source or destination information for transaction journal #%d is null. Cannot fix this one.', $transfer->id));
|
||||
|
||||
return;
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
|
||||
// both accounts must have currency preference:
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($this->isNoCurrencyPresent()) {
|
||||
$this->error(
|
||||
sprintf('Source or destination accounts for transaction journal #%d have no currency information. Cannot fix this one.', $transfer->id)
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
// fix source transaction having no currency.
|
||||
$this->fixSourceNoCurrency();
|
||||
|
||||
// fix source transaction having bad currency.
|
||||
$this->fixSourceUnmatchedCurrency();
|
||||
|
||||
// fix destination transaction having no currency.
|
||||
$this->fixDestNoCurrency();
|
||||
|
||||
// fix destination transaction having bad currency.
|
||||
$this->fixDestinationUnmatchedCurrency();
|
||||
|
||||
// remove foreign currency information if not necessary.
|
||||
$this->fixInvalidForeignCurrency();
|
||||
// correct foreign currency info if necessary.
|
||||
$this->fixMismatchedForeignCurrency();
|
||||
|
||||
// restore missing foreign currency amount.
|
||||
$this->fixSourceNullForeignAmount();
|
||||
|
||||
$this->fixDestNullForeignAmount();
|
||||
|
||||
// fix journal itself:
|
||||
$this->fixTransactionJournalCurrency($transfer);
|
||||
}
|
||||
}
|
||||
|
@@ -76,6 +76,7 @@ class UpgradeDatabase extends Command
|
||||
'firefly-iii:rename-account-meta',
|
||||
'firefly-iii:migrate-recurrence-meta',
|
||||
'firefly-iii:migrate-tag-locations',
|
||||
'firefly-iii:migrate-recurrence-type',
|
||||
|
||||
// there are 16 verify commands.
|
||||
'firefly-iii:fix-piggies',
|
||||
@@ -117,9 +118,9 @@ class UpgradeDatabase extends Command
|
||||
echo $result;
|
||||
}
|
||||
// set new DB version.
|
||||
app('fireflyconfig')->set('db_version', (int) config('firefly.db_version'));
|
||||
app('fireflyconfig')->set('db_version', (int)config('firefly.db_version'));
|
||||
// index will set FF3 version.
|
||||
app('fireflyconfig')->set('ff3_version', (string) config('firefly.version'));
|
||||
app('fireflyconfig')->set('ff3_version', (string)config('firefly.version'));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -83,6 +83,7 @@ class InstallController extends Controller
|
||||
'firefly-iii:rename-account-meta' => [],
|
||||
'firefly-iii:migrate-recurrence-meta' => [],
|
||||
'firefly-iii:migrate-tag-locations' => [],
|
||||
'firefly-iii:migrate-recurrence-type' => [],
|
||||
|
||||
// verify commands
|
||||
'firefly-iii:fix-piggies' => [],
|
||||
@@ -120,10 +121,10 @@ class InstallController extends Controller
|
||||
public function index()
|
||||
{
|
||||
// index will set FF3 version.
|
||||
app('fireflyconfig')->set('ff3_version', (string) config('firefly.version'));
|
||||
app('fireflyconfig')->set('ff3_version', (string)config('firefly.version'));
|
||||
|
||||
// set new DB version.
|
||||
app('fireflyconfig')->set('db_version', (int) config('firefly.db_version'));
|
||||
app('fireflyconfig')->set('db_version', (int)config('firefly.db_version'));
|
||||
|
||||
return prefixView('install.index');
|
||||
}
|
||||
@@ -156,7 +157,7 @@ class InstallController extends Controller
|
||||
*/
|
||||
public function runCommand(Request $request): JsonResponse
|
||||
{
|
||||
$requestIndex = (int) $request->get('index');
|
||||
$requestIndex = (int)$request->get('index');
|
||||
$response = [
|
||||
'hasNextCommand' => false,
|
||||
'done' => true,
|
||||
@@ -183,6 +184,7 @@ class InstallController extends Controller
|
||||
if (false === $result) {
|
||||
$response['errorMessage'] = $this->lastError;
|
||||
$response['error'] = true;
|
||||
|
||||
return response()->json($response);
|
||||
}
|
||||
$index++;
|
||||
@@ -197,6 +199,7 @@ class InstallController extends Controller
|
||||
/**
|
||||
* @param string $command
|
||||
* @param array $args
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function executeCommand(string $command, array $args): bool
|
||||
@@ -215,15 +218,17 @@ class InstallController extends Controller
|
||||
Log::error($e->getTraceAsString());
|
||||
if (strpos($e->getMessage(), 'open_basedir restriction in effect')) {
|
||||
$this->lastError = self::BASEDIR_ERROR;
|
||||
|
||||
return false;
|
||||
}
|
||||
$this->lastError = sprintf('%s %s', self::OTHER_ERROR, $e->getMessage());
|
||||
|
||||
return false;
|
||||
}
|
||||
// clear cache as well.
|
||||
Cache::clear();
|
||||
Preferences::mark();
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@@ -74,6 +74,8 @@ use Illuminate\Support\Collection;
|
||||
* @method static Builder|RecurrenceTransaction withTrashed()
|
||||
* @method static Builder|RecurrenceTransaction withoutTrashed()
|
||||
* @mixin Eloquent
|
||||
* @property int|null $transaction_type_id
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|RecurrenceTransaction whereTransactionTypeId($value)
|
||||
*/
|
||||
class RecurrenceTransaction extends Model
|
||||
{
|
||||
|
@@ -74,6 +74,9 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebhookAttempt whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebhookAttempt whereWebhookMessageId($value)
|
||||
* @mixin \Eloquent
|
||||
* @method static \Illuminate\Database\Query\Builder|WebhookAttempt onlyTrashed()
|
||||
* @method static \Illuminate\Database\Query\Builder|WebhookAttempt withTrashed()
|
||||
* @method static \Illuminate\Database\Query\Builder|WebhookAttempt withoutTrashed()
|
||||
*/
|
||||
class WebhookAttempt extends Model
|
||||
{
|
||||
|
Reference in New Issue
Block a user