mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
Update installation commands.
This commit is contained in:
parent
748d61fb8f
commit
a05d006fa7
@ -89,6 +89,7 @@ class CorrectOpeningBalanceCurrencies extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
Log::debug(sprintf('Done with %s', __METHOD__));
|
Log::debug(sprintf('Done with %s', __METHOD__));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,6 +134,7 @@ class CorrectOpeningBalanceCurrencies extends Command
|
|||||||
$account = $transaction->account()->first();
|
$account = $transaction->account()->first();
|
||||||
if (null !== $account && AccountType::INITIAL_BALANCE !== $account->accountType()->first()->type) {
|
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));
|
Log::debug(sprintf('Account of transaction #%d is opposite of IB account (%s).', $transaction->id, $account->accountType()->first()->type));
|
||||||
|
|
||||||
return $account;
|
return $account;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,6 +145,7 @@ class CorrectOpeningBalanceCurrencies extends Command
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Account $account
|
* @param Account $account
|
||||||
|
*
|
||||||
* @return TransactionCurrency
|
* @return TransactionCurrency
|
||||||
* @throws JsonException
|
* @throws JsonException
|
||||||
*/
|
*/
|
||||||
@ -156,15 +159,16 @@ class CorrectOpeningBalanceCurrencies extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param TransactionJournal $journal
|
* @param TransactionJournal $journal
|
||||||
* @param TransactionCurrency $currency
|
* @param TransactionCurrency $currency
|
||||||
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
private function setCurrency(TransactionJournal $journal, TransactionCurrency $currency): int
|
private function setCurrency(TransactionJournal $journal, TransactionCurrency $currency): int
|
||||||
{
|
{
|
||||||
Log::debug('Now in setCurrency');
|
Log::debug('Now in setCurrency');
|
||||||
$count = 0;
|
$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));
|
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->transaction_currency_id = $currency->id;
|
||||||
$journal->save();
|
$journal->save();
|
||||||
@ -173,8 +177,10 @@ class CorrectOpeningBalanceCurrencies extends Command
|
|||||||
|
|
||||||
/** @var Transaction $transaction */
|
/** @var Transaction $transaction */
|
||||||
foreach ($journal->transactions as $transaction) {
|
foreach ($journal->transactions as $transaction) {
|
||||||
if ((int) $transaction->transaction_currency_id !== (int) $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));
|
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->transaction_currency_id = $currency->id;
|
||||||
$transaction->save();
|
$transaction->save();
|
||||||
$count = 1;
|
$count = 1;
|
||||||
|
@ -50,8 +50,8 @@ class CreateAccessTokens extends Command
|
|||||||
/**
|
/**
|
||||||
* Execute the console command.
|
* Execute the console command.
|
||||||
*
|
*
|
||||||
* @throws Exception
|
|
||||||
* @return int
|
* @return int
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
{
|
{
|
||||||
|
@ -50,9 +50,9 @@ class DeleteEmptyGroups extends Command
|
|||||||
/**
|
/**
|
||||||
* Execute the console command.
|
* Execute the console command.
|
||||||
*
|
*
|
||||||
|
* @return int
|
||||||
* @throws Exception;
|
* @throws Exception;
|
||||||
*
|
*
|
||||||
* @return int
|
|
||||||
*/
|
*/
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
{
|
{
|
||||||
|
@ -62,6 +62,38 @@ class DeleteEmptyJournals extends Command
|
|||||||
return 0;
|
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
|
private function deleteEmptyJournals(): void
|
||||||
{
|
{
|
||||||
$start = microtime(true);
|
$start = microtime(true);
|
||||||
@ -90,36 +122,4 @@ class DeleteEmptyJournals extends Command
|
|||||||
$this->info(sprintf('Verified empty journals in %s seconds', $end));
|
$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.
|
* Execute the console command.
|
||||||
*
|
*
|
||||||
* @throws Exception
|
|
||||||
* @return int
|
* @return int
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
{
|
{
|
||||||
@ -66,45 +66,6 @@ class DeleteOrphanedTransactions extends Command
|
|||||||
return 0;
|
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
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
@ -124,7 +85,7 @@ class DeleteOrphanedTransactions extends Command
|
|||||||
);
|
);
|
||||||
/** @var stdClass $entry */
|
/** @var stdClass $entry */
|
||||||
foreach ($set as $entry) {
|
foreach ($set as $entry) {
|
||||||
$transaction = Transaction::find((int) $entry->transaction_id);
|
$transaction = Transaction::find((int)$entry->transaction_id);
|
||||||
$transaction->delete();
|
$transaction->delete();
|
||||||
$this->info(
|
$this->info(
|
||||||
sprintf(
|
sprintf(
|
||||||
@ -139,4 +100,43 @@ class DeleteOrphanedTransactions extends Command
|
|||||||
$this->info('No orphaned transactions.');
|
$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 */
|
/** @var Collection $meta */
|
||||||
$meta = AccountMeta::where('name', 'currency_id')->groupBy('data')->get(['data']);
|
$meta = AccountMeta::where('name', 'currency_id')->groupBy('data')->get(['data']);
|
||||||
foreach ($meta as $entry) {
|
foreach ($meta as $entry) {
|
||||||
$found[] = (int) $entry->data;
|
$found[] = (int)$entry->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get all from journals:
|
// get all from journals:
|
||||||
/** @var Collection $journals */
|
/** @var Collection $journals */
|
||||||
$journals = TransactionJournal::groupBy('transaction_currency_id')->get(['transaction_currency_id']);
|
$journals = TransactionJournal::groupBy('transaction_currency_id')->get(['transaction_currency_id']);
|
||||||
foreach ($journals as $entry) {
|
foreach ($journals as $entry) {
|
||||||
$found[] = (int) $entry->transaction_currency_id;
|
$found[] = (int)$entry->transaction_currency_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get all from transactions
|
// get all from transactions
|
||||||
/** @var Collection $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) {
|
foreach ($transactions as $entry) {
|
||||||
$found[] = (int) $entry->transaction_currency_id;
|
$found[] = (int)$entry->transaction_currency_id;
|
||||||
$found[] = (int) $entry->foreign_currency_id;
|
$found[] = (int)$entry->foreign_currency_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get all from budget limits
|
// get all from budget limits
|
||||||
/** @var Collection $limits */
|
/** @var Collection $limits */
|
||||||
$limits = BudgetLimit::groupBy('transaction_currency_id')->get(['transaction_currency_id']);
|
$limits = BudgetLimit::groupBy('transaction_currency_id')->get(['transaction_currency_id']);
|
||||||
foreach ($limits as $entry) {
|
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_unique($found));
|
||||||
$found = array_values(array_filter($found, function (int $currencyId) {
|
$found = array_values(
|
||||||
return $currencyId !== 0;
|
array_filter(
|
||||||
}));
|
$found, function (int $currencyId) {
|
||||||
|
return $currencyId !== 0;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
$message = sprintf('%d different currencies are currently in use.', count($found));
|
$message = sprintf('%d different currencies are currently in use.', count($found));
|
||||||
$this->info($message);
|
$this->info($message);
|
||||||
Log::debug($message, $found);
|
Log::debug($message, $found);
|
||||||
|
@ -39,11 +39,13 @@ class FixAccountTypes extends Command
|
|||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The console command description.
|
* The console command description.
|
||||||
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $description = 'Make sure all journals have the correct from/to account types.';
|
protected $description = 'Make sure all journals have the correct from/to account types.';
|
||||||
/**
|
/**
|
||||||
* The name and signature of the console command.
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $signature = 'firefly-iii:fix-account-types';
|
protected $signature = 'firefly-iii:fix-account-types';
|
||||||
@ -54,6 +56,7 @@ class FixAccountTypes extends Command
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the console command.
|
* Execute the console command.
|
||||||
|
*
|
||||||
* @return int
|
* @return int
|
||||||
* @throws FireflyException
|
* @throws FireflyException
|
||||||
*/
|
*/
|
||||||
@ -84,11 +87,87 @@ class FixAccountTypes extends Command
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
|
||||||
|
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
|
||||||
|
* be called from the handle method instead of using the constructor to initialize the command.
|
||||||
|
*
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
*/
|
||||||
|
private function stupidLaravel(): void
|
||||||
|
{
|
||||||
|
$this->count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param TransactionJournal $journal
|
||||||
|
*
|
||||||
|
* @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 TransactionJournal $journal
|
||||||
* @param string $type
|
* @param string $type
|
||||||
* @param Transaction $source
|
* @param Transaction $source
|
||||||
* @param Transaction $dest
|
* @param Transaction $dest
|
||||||
|
*
|
||||||
* @throws FireflyException
|
* @throws FireflyException
|
||||||
*/
|
*/
|
||||||
private function fixJournal(TransactionJournal $journal, string $type, Transaction $source, Transaction $dest): void
|
private function fixJournal(TransactionJournal $journal, string $type, Transaction $source, Transaction $dest): void
|
||||||
@ -132,7 +211,10 @@ class FixAccountTypes extends Command
|
|||||||
$result = $this->factory->findOrCreate($dest->account->name, AccountType::EXPENSE);
|
$result = $this->factory->findOrCreate($dest->account->name, AccountType::EXPENSE);
|
||||||
$dest->account()->associate($result);
|
$dest->account()->associate($result);
|
||||||
$dest->save();
|
$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);
|
$this->info($message);
|
||||||
Log::debug($message);
|
Log::debug($message);
|
||||||
$this->inspectJournal($journal);
|
$this->inspectJournal($journal);
|
||||||
@ -145,7 +227,10 @@ class FixAccountTypes extends Command
|
|||||||
$oldSource = $dest->account;
|
$oldSource = $dest->account;
|
||||||
$source->account()->associate($result);
|
$source->account()->associate($result);
|
||||||
$source->save();
|
$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);
|
$this->info($message);
|
||||||
Log::debug($message);
|
Log::debug($message);
|
||||||
$this->inspectJournal($journal);
|
$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')
|
::groupBy('transaction_group_id')
|
||||||
->get(['transaction_group_id', DB::raw('COUNT(transaction_group_id) as the_count')]);
|
->get(['transaction_group_id', DB::raw('COUNT(transaction_group_id) as the_count')]);
|
||||||
foreach ($res as $journal) {
|
foreach ($res as $journal) {
|
||||||
if ((int) $journal->the_count > 1) {
|
if ((int)$journal->the_count > 1) {
|
||||||
$groups[] = (int) $journal->transaction_group_id;
|
$groups[] = (int)$journal->transaction_group_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$handler = new UpdatedGroupEventHandler;
|
$handler = new UpdatedGroupEventHandler;
|
||||||
foreach($groups as $groupId) {
|
foreach ($groups as $groupId) {
|
||||||
$group = TransactionGroup::find($groupId);
|
$group = TransactionGroup::find($groupId);
|
||||||
$event = new UpdatedTransactionGroup($group);
|
$event = new UpdatedTransactionGroup($group);
|
||||||
$handler->unifyAccounts($event);
|
$handler->unifyAccounts($event);
|
||||||
|
@ -69,7 +69,7 @@ class FixLongDescriptions extends Command
|
|||||||
$groups = TransactionGroup::get(['id', 'title']);
|
$groups = TransactionGroup::get(['id', 'title']);
|
||||||
/** @var TransactionGroup $group */
|
/** @var TransactionGroup $group */
|
||||||
foreach ($groups as $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->title = substr($group->title, 0, self::MAX_LENGTH);
|
||||||
$group->save();
|
$group->save();
|
||||||
$this->line(sprintf('Truncated description of transaction group #%d', $group->id));
|
$this->line(sprintf('Truncated description of transaction group #%d', $group->id));
|
||||||
|
@ -73,18 +73,6 @@ class FixRecurringTransactions extends Command
|
|||||||
return 0;
|
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
|
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
|
||||||
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
|
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
|
||||||
@ -98,6 +86,18 @@ class FixRecurringTransactions extends Command
|
|||||||
$this->userRepos = app(UserRepositoryInterface::class);
|
$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
|
* @param User $user
|
||||||
*/
|
*/
|
||||||
|
@ -79,19 +79,6 @@ class FixTransactionTypes extends Command
|
|||||||
return 0;
|
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.
|
* Collect all transaction journals.
|
||||||
*
|
*
|
||||||
@ -120,7 +107,7 @@ class FixTransactionTypes extends Command
|
|||||||
|
|
||||||
return false;
|
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) {
|
if ($expectedType !== $type) {
|
||||||
$this->line(sprintf('Transaction journal #%d was of type "%s" but is corrected to "%s"', $journal->id, $type, $expectedType));
|
$this->line(sprintf('Transaction journal #%d was of type "%s" but is corrected to "%s"', $journal->id, $type, $expectedType));
|
||||||
$this->changeJournal($journal, $expectedType);
|
$this->changeJournal($journal, $expectedType);
|
||||||
@ -134,8 +121,37 @@ class FixTransactionTypes extends Command
|
|||||||
/**
|
/**
|
||||||
* @param TransactionJournal $journal
|
* @param TransactionJournal $journal
|
||||||
*
|
*
|
||||||
* @throws FireflyException
|
|
||||||
* @return Account
|
* @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
|
private function getDestinationAccount(TransactionJournal $journal): Account
|
||||||
{
|
{
|
||||||
@ -162,30 +178,14 @@ class FixTransactionTypes extends Command
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param TransactionJournal $journal
|
* @param TransactionJournal $journal
|
||||||
*
|
* @param string $expectedType
|
||||||
* @throws FireflyException
|
|
||||||
* @return Account
|
|
||||||
*/
|
*/
|
||||||
private function getSourceAccount(TransactionJournal $journal): Account
|
private function changeJournal(TransactionJournal $journal, string $expectedType): void
|
||||||
{
|
{
|
||||||
$collection = $journal->transactions->filter(
|
$type = TransactionType::whereType($expectedType)->first();
|
||||||
static function (Transaction $transaction) {
|
if (null !== $type) {
|
||||||
return $transaction->amount < 0;
|
$journal->transaction_type_id = $type->id;
|
||||||
}
|
$journal->save();
|
||||||
);
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,10 +56,10 @@ class RemoveBills extends Command
|
|||||||
$start = microtime(true);
|
$start = microtime(true);
|
||||||
/** @var TransactionType $withdrawal */
|
/** @var TransactionType $withdrawal */
|
||||||
$withdrawal = TransactionType::where('type', TransactionType::WITHDRAWAL)->first();
|
$withdrawal = TransactionType::where('type', TransactionType::WITHDRAWAL)->first();
|
||||||
if(null === $withdrawal) {
|
if (null === $withdrawal) {
|
||||||
return 0;
|
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 */
|
/** @var TransactionJournal $journal */
|
||||||
foreach ($journals as $journal) {
|
foreach ($journals as $journal) {
|
||||||
$this->line(sprintf('Transaction journal #%d should not be linked to bill #%d.', $journal->id, $journal->bill_id));
|
$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
|
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
|
||||||
* @param array $data
|
* 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');
|
$this->journalRepository = app(JournalRepositoryInterface::class);
|
||||||
foreach ($data as $key => $content) {
|
$this->accountRepository = app(AccountRepositoryInterface::class);
|
||||||
$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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -283,16 +191,108 @@ class ExportData extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
|
* @param string $field
|
||||||
* 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
|
* @return Carbon
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
private function stupidLaravel(): void
|
private function getDateParameter(string $field): Carbon
|
||||||
{
|
{
|
||||||
$this->journalRepository = app(JournalRepositoryInterface::class);
|
$date = Carbon::now()->subYear();
|
||||||
$this->accountRepository = app(AccountRepositoryInterface::class);
|
$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;
|
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.
|
* Report on budgets with no transactions or journals.
|
||||||
*/
|
*/
|
||||||
@ -188,4 +143,49 @@ class ReportEmptyObjects extends Command
|
|||||||
$this->line($line);
|
$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 */
|
/** @var User $user */
|
||||||
foreach ($userRepository->all() as $user) {
|
foreach ($userRepository->all() as $user) {
|
||||||
$sum = (string) $user->transactions()->sum('amount');
|
$sum = (string)$user->transactions()->sum('amount');
|
||||||
if (0 !== bccomp($sum, '0')) {
|
if (0 !== bccomp($sum, '0')) {
|
||||||
$message = sprintf('Error: Transactions for user #%d (%s) are off by %s!', $user->id, $user->email, $sum);
|
$message = sprintf('Error: Transactions for user #%d (%s) are off by %s!', $user->id, $user->email, $sum);
|
||||||
$this->error($message);
|
$this->error($message);
|
||||||
|
@ -59,38 +59,6 @@ class RestoreOAuthKeys extends Command
|
|||||||
return 0;
|
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');
|
$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();
|
OAuthKeys::storeKeysInDB();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function restoreKeysFromDB(): void
|
||||||
|
{
|
||||||
|
OAuthKeys::restoreKeysFromDB();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,6 +102,7 @@ class ApplyRules extends Command
|
|||||||
$result = $this->verifyInput();
|
$result = $this->verifyInput();
|
||||||
if (false === $result) {
|
if (false === $result) {
|
||||||
app('telemetry')->feature('system.command.errored', $this->signature);
|
app('telemetry')->feature('system.command.errored', $this->signature);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,6 +122,7 @@ class ApplyRules extends Command
|
|||||||
$this->warn(' --all_rules');
|
$this->warn(' --all_rules');
|
||||||
|
|
||||||
app('telemetry')->feature('system.command.errored', $this->signature);
|
app('telemetry')->feature('system.command.errored', $this->signature);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,7 +134,7 @@ class ApplyRules extends Command
|
|||||||
|
|
||||||
// add the accounts as filter:
|
// add the accounts as filter:
|
||||||
$filterAccountList = [];
|
$filterAccountList = [];
|
||||||
foreach($this->accounts as $account) {
|
foreach ($this->accounts as $account) {
|
||||||
$filterAccountList[] = $account->id;
|
$filterAccountList[] = $account->id;
|
||||||
}
|
}
|
||||||
$list = implode(',', $filterAccountList);
|
$list = implode(',', $filterAccountList);
|
||||||
@ -157,49 +159,6 @@ class ApplyRules extends Command
|
|||||||
return 0;
|
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
|
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
|
||||||
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
|
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
|
||||||
@ -271,7 +230,7 @@ class ApplyRules extends Command
|
|||||||
|
|
||||||
|
|
||||||
foreach ($accountList as $accountId) {
|
foreach ($accountList as $accountId) {
|
||||||
$accountId = (int) $accountId;
|
$accountId = (int)$accountId;
|
||||||
$account = $accountRepository->findNull($accountId);
|
$account = $accountRepository->findNull($accountId);
|
||||||
if (null !== $account && in_array($account->accountType->type, $this->acceptedAccounts, true)) {
|
if (null !== $account && in_array($account->accountType->type, $this->acceptedAccounts, true)) {
|
||||||
$finalList->push($account);
|
$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
|
* @return bool
|
||||||
*/
|
*/
|
||||||
@ -343,7 +266,7 @@ class ApplyRules extends Command
|
|||||||
}
|
}
|
||||||
// @codeCoverageIgnoreEnd
|
// @codeCoverageIgnoreEnd
|
||||||
foreach ($ruleGroupList as $ruleGroupId) {
|
foreach ($ruleGroupList as $ruleGroupId) {
|
||||||
$ruleGroup = $this->ruleGroupRepository->find((int) $ruleGroupId);
|
$ruleGroup = $this->ruleGroupRepository->find((int)$ruleGroupId);
|
||||||
if ($ruleGroup->active) {
|
if ($ruleGroup->active) {
|
||||||
$this->ruleGroupSelection[] = $ruleGroup->id;
|
$this->ruleGroupSelection[] = $ruleGroup->id;
|
||||||
}
|
}
|
||||||
@ -376,7 +299,7 @@ class ApplyRules extends Command
|
|||||||
// @codeCoverageIgnoreEnd
|
// @codeCoverageIgnoreEnd
|
||||||
|
|
||||||
foreach ($ruleList as $ruleId) {
|
foreach ($ruleList as $ruleId) {
|
||||||
$rule = $this->ruleRepository->find((int) $ruleId);
|
$rule = $this->ruleRepository->find((int)$ruleId);
|
||||||
if (null !== $rule && $rule->active) {
|
if (null !== $rule && $rule->active) {
|
||||||
$this->ruleSelection[] = $rule->id;
|
$this->ruleSelection[] = $rule->id;
|
||||||
}
|
}
|
||||||
@ -384,4 +307,83 @@ class ApplyRules extends Command
|
|||||||
|
|
||||||
return true;
|
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;
|
$date = null;
|
||||||
try {
|
try {
|
||||||
$date = new Carbon($this->option('date'));
|
$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')));
|
$this->error(sprintf('"%s" is not a valid date', $this->option('date')));
|
||||||
$e->getMessage();
|
$e->getMessage();
|
||||||
}
|
}
|
||||||
$force = (bool) $this->option('force');
|
$force = (bool)$this->option('force');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fire recurring transaction cron job.
|
* 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.');
|
$this->info('More feedback on the cron jobs can be found in the log files.');
|
||||||
|
|
||||||
app('telemetry')->feature('system.command.executed', $this->signature);
|
app('telemetry')->feature('system.command.executed', $this->signature);
|
||||||
|
|
||||||
return 0;
|
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 bool $force
|
||||||
* @param Carbon|null $date
|
* @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 bool $force
|
||||||
* @param Carbon|null $date
|
* @param Carbon|null $date
|
||||||
|
@ -92,27 +92,6 @@ class AccountCurrencies extends Command
|
|||||||
return 0;
|
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
|
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
|
||||||
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
|
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
|
||||||
@ -127,6 +106,66 @@ class AccountCurrencies extends Command
|
|||||||
$this->count = 0;
|
$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 Account $account
|
||||||
* @param TransactionCurrency $currency
|
* @param TransactionCurrency $currency
|
||||||
@ -136,13 +175,13 @@ class AccountCurrencies extends Command
|
|||||||
Log::debug(sprintf('Now in updateAccount(%d, %s)', $account->id, $currency->code));
|
Log::debug(sprintf('Now in updateAccount(%d, %s)', $account->id, $currency->code));
|
||||||
$this->accountRepos->setUser($account->user);
|
$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));
|
Log::debug(sprintf('Account currency is #%d', $accountCurrency));
|
||||||
|
|
||||||
$openingBalance = $this->accountRepos->getOpeningBalance($account);
|
$openingBalance = $this->accountRepos->getOpeningBalance($account);
|
||||||
$obCurrency = 0;
|
$obCurrency = 0;
|
||||||
if (null !== $openingBalance) {
|
if (null !== $openingBalance) {
|
||||||
$obCurrency = (int) $openingBalance->transaction_currency_id;
|
$obCurrency = (int)$openingBalance->transaction_currency_id;
|
||||||
Log::debug('Account has opening balance.');
|
Log::debug('Account has opening balance.');
|
||||||
}
|
}
|
||||||
Log::debug(sprintf('Account OB currency is #%d.', $obCurrency));
|
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()');
|
app('fireflyconfig')->set(self::CONFIG_NAME, true);
|
||||||
$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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ class AppendBudgetLimitPeriods extends Command
|
|||||||
|
|
||||||
$this->theresNoLimit();
|
$this->theresNoLimit();
|
||||||
|
|
||||||
$this->markAsExecuted();
|
$this->markAsExecuted();
|
||||||
|
|
||||||
$end = round(microtime(true) - $start, 2);
|
$end = round(microtime(true) - $start, 2);
|
||||||
$this->info(sprintf('Fixed budget limits in %s seconds.', $end));
|
$this->info(sprintf('Fixed budget limits in %s seconds.', $end));
|
||||||
@ -100,6 +100,44 @@ class AppendBudgetLimitPeriods extends Command
|
|||||||
return false; // @codeCoverageIgnore
|
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
|
* @param BudgetLimit $limit
|
||||||
*
|
*
|
||||||
@ -160,37 +198,4 @@ class AppendBudgetLimitPeriods extends Command
|
|||||||
{
|
{
|
||||||
app('fireflyconfig')->set(self::CONFIG_NAME, true);
|
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();
|
$configVar = app('fireflyconfig')->get(MigrateToGroups::CONFIG_NAME, false);
|
||||||
$array = [];
|
if (null !== $configVar) {
|
||||||
$chunks = array_chunk($transactions, 500);
|
return (bool)$configVar->data;
|
||||||
|
|
||||||
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
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -129,33 +102,12 @@ class BackToJournals extends Command
|
|||||||
{
|
{
|
||||||
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||||
if (null !== $configVar) {
|
if (null !== $configVar) {
|
||||||
return (bool) $configVar->data;
|
return (bool)$configVar->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // @codeCoverageIgnore
|
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
|
* @param TransactionJournal $journal
|
||||||
*/
|
*/
|
||||||
@ -213,7 +185,7 @@ class BackToJournals extends Command
|
|||||||
// both have a budget, but they don't match.
|
// both have a budget, but they don't match.
|
||||||
if (null !== $budget && null !== $journalBudget && $budget->id !== $journalBudget->id) {
|
if (null !== $budget && null !== $journalBudget && $budget->id !== $journalBudget->id) {
|
||||||
// sync to journal:
|
// sync to journal:
|
||||||
$journal->budgets()->sync([(int) $budget->id]);
|
$journal->budgets()->sync([(int)$budget->id]);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -221,7 +193,7 @@ class BackToJournals extends Command
|
|||||||
// transaction has a budget, but the journal doesn't.
|
// transaction has a budget, but the journal doesn't.
|
||||||
if (null !== $budget && null === $journalBudget) {
|
if (null !== $budget && null === $journalBudget) {
|
||||||
// sync to journal:
|
// 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
|
* @param TransactionJournal $journal
|
||||||
*/
|
*/
|
||||||
@ -272,12 +264,20 @@ class BackToJournals extends Command
|
|||||||
// both have a category, but they don't match.
|
// both have a category, but they don't match.
|
||||||
if (null !== $category && null !== $journalCategory && $category->id !== $journalCategory->id) {
|
if (null !== $category && null !== $journalCategory && $category->id !== $journalCategory->id) {
|
||||||
// sync to journal:
|
// sync to journal:
|
||||||
$journal->categories()->sync([(int) $category->id]);
|
$journal->categories()->sync([(int)$category->id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// transaction has a category, but the journal doesn't.
|
// transaction has a category, but the journal doesn't.
|
||||||
if (null !== $category && null === $journalCategory) {
|
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);
|
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||||
if (null !== $configVar) {
|
if (null !== $configVar) {
|
||||||
return (bool) $configVar->data;
|
return (bool)$configVar->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // @codeCoverageIgnore
|
return false; // @codeCoverageIgnore
|
||||||
|
@ -102,7 +102,7 @@ class CCLiabilities extends Command
|
|||||||
{
|
{
|
||||||
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||||
if (null !== $configVar) {
|
if (null !== $configVar) {
|
||||||
return (bool) $configVar->data;
|
return (bool)$configVar->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // @codeCoverageIgnore
|
return false; // @codeCoverageIgnore
|
||||||
|
@ -72,7 +72,7 @@ class MigrateAttachments extends Command
|
|||||||
foreach ($attachments as $att) {
|
foreach ($attachments as $att) {
|
||||||
|
|
||||||
// move description:
|
// move description:
|
||||||
$attDescription = (string) $att->description;
|
$attDescription = (string)$att->description;
|
||||||
if ('' !== $attDescription) {
|
if ('' !== $attDescription) {
|
||||||
|
|
||||||
// find or create note:
|
// find or create note:
|
||||||
@ -112,7 +112,7 @@ class MigrateAttachments extends Command
|
|||||||
{
|
{
|
||||||
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||||
if (null !== $configVar) {
|
if (null !== $configVar) {
|
||||||
return (bool) $configVar->data;
|
return (bool)$configVar->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // @codeCoverageIgnore
|
return false; // @codeCoverageIgnore
|
||||||
|
@ -111,7 +111,7 @@ class MigrateJournalNotes extends Command
|
|||||||
{
|
{
|
||||||
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||||
if (null !== $configVar) {
|
if (null !== $configVar) {
|
||||||
return (bool) $configVar->data;
|
return (bool)$configVar->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // @codeCoverageIgnore
|
return false; // @codeCoverageIgnore
|
||||||
|
@ -85,19 +85,26 @@ class MigrateRecurrenceMeta extends Command
|
|||||||
{
|
{
|
||||||
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||||
if (null !== $configVar) {
|
if (null !== $configVar) {
|
||||||
return (bool) $configVar->data;
|
return (bool)$configVar->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // @codeCoverageIgnore
|
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;
|
app('fireflyconfig')->set(self::CONFIG_NAME, true);
|
||||||
// get all recurrence meta data:
|
|
||||||
$collection = RecurrenceMeta::with('recurrence')->get();
|
|
||||||
/** @var RecurrenceMeta $meta */
|
|
||||||
foreach ($collection as $meta) {
|
|
||||||
$count += $this->migrateEntry($meta);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $count;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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 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
|
* @param Tag $tag
|
||||||
*
|
*
|
||||||
@ -81,28 +105,6 @@ class MigrateTagLocations extends Command
|
|||||||
return null !== $tag->latitude && null !== $tag->longitude && null !== $tag->zoomLevel;
|
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
|
* @param Tag $tag
|
||||||
*/
|
*/
|
||||||
@ -121,15 +123,12 @@ class MigrateTagLocations extends Command
|
|||||||
$tag->save();
|
$tag->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function migrateTagLocations(): void
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function markAsExecuted(): void
|
||||||
{
|
{
|
||||||
$tags = Tag::get();
|
app('fireflyconfig')->set(self::CONFIG_NAME, true);
|
||||||
/** @var Tag $tag */
|
|
||||||
foreach ($tags as $tag) {
|
|
||||||
if ($this->hasLocationDetails($tag)) {
|
|
||||||
$this->migrateLocationDetails($tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -112,122 +112,19 @@ class MigrateToGroups extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param TransactionJournal $journal
|
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
|
||||||
* @param Transaction $transaction
|
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
|
||||||
|
* 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(
|
$this->count = 0;
|
||||||
static function (Transaction $subject) use ($transaction) {
|
$this->journalRepository = app(JournalRepositoryInterface::class);
|
||||||
$amount = (float) $transaction->amount * -1 === (float) $subject->amount;
|
$this->service = app(JournalDestroyService::class);
|
||||||
$identifier = $transaction->identifier === $subject->identifier;
|
$this->groupFactory = app(TransactionGroupFactory::class);
|
||||||
Log::debug(sprintf('Amount the same? %s', var_export($amount, true)));
|
$this->cliRepository = app(JournalCLIRepositoryInterface::class);
|
||||||
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++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -237,32 +134,12 @@ class MigrateToGroups extends Command
|
|||||||
{
|
{
|
||||||
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||||
if (null !== $configVar) {
|
if (null !== $configVar) {
|
||||||
return (bool) $configVar->data;
|
return (bool)$configVar->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // @codeCoverageIgnore
|
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
|
* @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);
|
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.
|
* Execute the console command.
|
||||||
*
|
*
|
||||||
* @throws FireflyException
|
|
||||||
* @return int
|
* @return int
|
||||||
|
* @throws FireflyException
|
||||||
*/
|
*/
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
{
|
{
|
||||||
@ -103,6 +103,22 @@ class MigrateToRules extends Command
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
|
||||||
|
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
|
||||||
|
* be called from the handle method instead of using the constructor to initialize the command.
|
||||||
|
*
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
*/
|
||||||
|
private function stupidLaravel(): void
|
||||||
|
{
|
||||||
|
$this->count = 0;
|
||||||
|
$this->userRepository = app(UserRepositoryInterface::class);
|
||||||
|
$this->ruleGroupRepository = app(RuleGroupRepositoryInterface::class);
|
||||||
|
$this->billRepository = app(BillRepositoryInterface::class);
|
||||||
|
$this->ruleRepository = app(RuleRepositoryInterface::class);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
@ -110,18 +126,46 @@ class MigrateToRules extends Command
|
|||||||
{
|
{
|
||||||
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||||
if (null !== $configVar) {
|
if (null !== $configVar) {
|
||||||
return (bool) $configVar->data;
|
return (bool)$configVar->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // @codeCoverageIgnore
|
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,
|
'active' => true,
|
||||||
'strict' => false,
|
'strict' => false,
|
||||||
'stop_processing' => false, // field is no longer used.
|
'stop_processing' => false, // field is no longer used.
|
||||||
'title' => (string) trans('firefly.rule_for_bill_title', ['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),
|
'description' => (string)trans('firefly.rule_for_bill_description', ['name' => $bill->name], $language->data),
|
||||||
'trigger' => 'store-journal',
|
'trigger' => 'store-journal',
|
||||||
'triggers' => [
|
'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);
|
app('fireflyconfig')->set(self::CONFIG_NAME, true);
|
||||||
$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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
$this->count = 0;
|
||||||
if (array_key_exists($accountId, $this->accountCurrencies) && 0 === $this->accountCurrencies[$accountId]) {
|
$this->accountCurrencies = [];
|
||||||
return null; // @codeCoverageIgnore
|
$this->accountRepos = app(AccountRepositoryInterface::class);
|
||||||
}
|
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
|
||||||
if (array_key_exists($accountId, $this->accountCurrencies) && $this->accountCurrencies[$accountId] instanceof TransactionCurrency) {
|
$this->journalRepos = app(JournalRepositoryInterface::class);
|
||||||
return $this->accountCurrencies[$accountId]; // @codeCoverageIgnore
|
$this->cliRepos = app(JournalCLIRepositoryInterface::class);
|
||||||
}
|
|
||||||
$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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -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,]
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/** @var TransactionJournal $journal */
|
||||||
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
|
foreach ($set as $journal) {
|
||||||
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
|
$this->updateJournalCurrency($journal);
|
||||||
* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -256,20 +201,75 @@ class OtherCurrenciesCorrections extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This routine verifies that withdrawals, deposits and opening balances have the correct currency settings for
|
* Gets the transaction that determines the transaction that "leads" and will determine
|
||||||
* the accounts they are linked to.
|
* the currency to be used by all transactions, and the journal itself.
|
||||||
* Both source and destination must match the respective currency preference of the related asset account.
|
*
|
||||||
* So FF3 must verify all transactions.
|
* @param TransactionJournal $journal
|
||||||
|
*
|
||||||
|
* @return Transaction|null
|
||||||
*/
|
*/
|
||||||
private function updateOtherJournalsCurrencies(): void
|
private function getLeadTransaction(TransactionJournal $journal): ?Transaction
|
||||||
{
|
{
|
||||||
$set = $this->cliRepos->getAllJournals(
|
/** @var Transaction $lead */
|
||||||
[TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::OPENING_BALANCE, TransactionType::RECONCILIATION,]
|
$lead = null;
|
||||||
);
|
switch ($journal->transactionType->type) {
|
||||||
|
default:
|
||||||
/** @var TransactionJournal $journal */
|
break;
|
||||||
foreach ($set as $journal) {
|
case TransactionType::WITHDRAWAL:
|
||||||
$this->updateJournalCurrency($journal);
|
$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);
|
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||||
if (null !== $configVar) {
|
if (null !== $configVar) {
|
||||||
return (bool) $configVar->data;
|
return (bool)$configVar->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // @codeCoverageIgnore
|
return false; // @codeCoverageIgnore
|
||||||
|
@ -105,60 +105,6 @@ class TransactionIdentifier extends Command
|
|||||||
return 0;
|
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
|
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
|
||||||
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
|
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
|
||||||
@ -173,6 +119,19 @@ class TransactionIdentifier extends Command
|
|||||||
$this->count = 0;
|
$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
|
* Grab all positive transactions from this journal that are not deleted. for each one, grab the negative opposing one
|
||||||
* which has 0 as an identifier and give it the same identifier.
|
* which has 0 as an identifier and give it the same identifier.
|
||||||
@ -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 JournalCLIRepositoryInterface $cliRepos;
|
||||||
private int $count;
|
private int $count;
|
||||||
|
|
||||||
private ?Account $destinationAccount;
|
private ?Account $destinationAccount;
|
||||||
private ?TransactionCurrency $destinationCurrency;
|
private ?TransactionCurrency $destinationCurrency;
|
||||||
private ?Transaction $destinationTransaction;
|
private ?Transaction $destinationTransaction;
|
||||||
private ?Account $sourceAccount;
|
private ?Account $sourceAccount;
|
||||||
private ?TransactionCurrency $sourceCurrency;
|
private ?TransactionCurrency $sourceCurrency;
|
||||||
private ?Transaction $sourceTransaction;
|
private ?Transaction $sourceTransaction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the console command.
|
* Execute the console command.
|
||||||
@ -99,6 +99,313 @@ class TransferCurrenciesCorrections extends Command
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
|
||||||
|
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
|
||||||
|
* be called from the handle method instead of using the constructor to initialize the command.
|
||||||
|
*
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
*/
|
||||||
|
private function stupidLaravel(): void
|
||||||
|
{
|
||||||
|
$this->count = 0;
|
||||||
|
$this->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
|
* The destination transaction must have a currency. If not, it will be added by
|
||||||
* taking it from the destination account's preference.
|
* 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
|
* The destination transaction must have the correct currency. If not, it will be set by
|
||||||
* taking it from the destination account's preference.
|
* 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
|
* 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.
|
* 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
|
* If the foreign amount of the destination transaction is null, but that of the other isn't, use this piece of code
|
||||||
* taking it from the source account's preference.
|
* to restore it.
|
||||||
*/
|
*/
|
||||||
private function fixSourceUnmatchedCurrency(): void
|
private function fixDestNullForeignAmount(): void
|
||||||
{
|
{
|
||||||
if (null !== $this->sourceCurrency
|
if (null === $this->destinationTransaction->foreign_amount && null !== $this->sourceTransaction->foreign_amount) {
|
||||||
&& null === $this->sourceTransaction->foreign_amount
|
$this->destinationTransaction->foreign_amount = bcmul((string)$this->sourceTransaction->foreign_amount, '-1');
|
||||||
&& (int)$this->sourceTransaction->transaction_currency_id !== (int)$this->sourceCurrency->id
|
$this->destinationTransaction->save();
|
||||||
) {
|
|
||||||
$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->count++;
|
||||||
$this->sourceTransaction->transaction_currency_id = (int)$this->sourceCurrency->id;
|
Log::debug(
|
||||||
$this->sourceTransaction->save();
|
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);
|
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:rename-account-meta',
|
||||||
'firefly-iii:migrate-recurrence-meta',
|
'firefly-iii:migrate-recurrence-meta',
|
||||||
'firefly-iii:migrate-tag-locations',
|
'firefly-iii:migrate-tag-locations',
|
||||||
|
'firefly-iii:migrate-recurrence-type',
|
||||||
|
|
||||||
// there are 16 verify commands.
|
// there are 16 verify commands.
|
||||||
'firefly-iii:fix-piggies',
|
'firefly-iii:fix-piggies',
|
||||||
@ -117,9 +118,9 @@ class UpgradeDatabase extends Command
|
|||||||
echo $result;
|
echo $result;
|
||||||
}
|
}
|
||||||
// set new DB 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'));
|
||||||
// index will set FF3 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,7 @@ class InstallController extends Controller
|
|||||||
'firefly-iii:rename-account-meta' => [],
|
'firefly-iii:rename-account-meta' => [],
|
||||||
'firefly-iii:migrate-recurrence-meta' => [],
|
'firefly-iii:migrate-recurrence-meta' => [],
|
||||||
'firefly-iii:migrate-tag-locations' => [],
|
'firefly-iii:migrate-tag-locations' => [],
|
||||||
|
'firefly-iii:migrate-recurrence-type' => [],
|
||||||
|
|
||||||
// verify commands
|
// verify commands
|
||||||
'firefly-iii:fix-piggies' => [],
|
'firefly-iii:fix-piggies' => [],
|
||||||
@ -120,10 +121,10 @@ class InstallController extends Controller
|
|||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
// index will set FF3 version.
|
// 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.
|
// 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');
|
return prefixView('install.index');
|
||||||
}
|
}
|
||||||
@ -156,7 +157,7 @@ class InstallController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function runCommand(Request $request): JsonResponse
|
public function runCommand(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
$requestIndex = (int) $request->get('index');
|
$requestIndex = (int)$request->get('index');
|
||||||
$response = [
|
$response = [
|
||||||
'hasNextCommand' => false,
|
'hasNextCommand' => false,
|
||||||
'done' => true,
|
'done' => true,
|
||||||
@ -183,6 +184,7 @@ class InstallController extends Controller
|
|||||||
if (false === $result) {
|
if (false === $result) {
|
||||||
$response['errorMessage'] = $this->lastError;
|
$response['errorMessage'] = $this->lastError;
|
||||||
$response['error'] = true;
|
$response['error'] = true;
|
||||||
|
|
||||||
return response()->json($response);
|
return response()->json($response);
|
||||||
}
|
}
|
||||||
$index++;
|
$index++;
|
||||||
@ -197,6 +199,7 @@ class InstallController extends Controller
|
|||||||
/**
|
/**
|
||||||
* @param string $command
|
* @param string $command
|
||||||
* @param array $args
|
* @param array $args
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
private function executeCommand(string $command, array $args): bool
|
private function executeCommand(string $command, array $args): bool
|
||||||
@ -215,15 +218,17 @@ class InstallController extends Controller
|
|||||||
Log::error($e->getTraceAsString());
|
Log::error($e->getTraceAsString());
|
||||||
if (strpos($e->getMessage(), 'open_basedir restriction in effect')) {
|
if (strpos($e->getMessage(), 'open_basedir restriction in effect')) {
|
||||||
$this->lastError = self::BASEDIR_ERROR;
|
$this->lastError = self::BASEDIR_ERROR;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$this->lastError = sprintf('%s %s', self::OTHER_ERROR, $e->getMessage());
|
$this->lastError = sprintf('%s %s', self::OTHER_ERROR, $e->getMessage());
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// clear cache as well.
|
// clear cache as well.
|
||||||
Cache::clear();
|
Cache::clear();
|
||||||
Preferences::mark();
|
Preferences::mark();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,6 +74,8 @@ use Illuminate\Support\Collection;
|
|||||||
* @method static Builder|RecurrenceTransaction withTrashed()
|
* @method static Builder|RecurrenceTransaction withTrashed()
|
||||||
* @method static Builder|RecurrenceTransaction withoutTrashed()
|
* @method static Builder|RecurrenceTransaction withoutTrashed()
|
||||||
* @mixin Eloquent
|
* @mixin Eloquent
|
||||||
|
* @property int|null $transaction_type_id
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|RecurrenceTransaction whereTransactionTypeId($value)
|
||||||
*/
|
*/
|
||||||
class RecurrenceTransaction extends Model
|
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 whereUpdatedAt($value)
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|WebhookAttempt whereWebhookMessageId($value)
|
* @method static \Illuminate\Database\Eloquent\Builder|WebhookAttempt whereWebhookMessageId($value)
|
||||||
* @mixin \Eloquent
|
* @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
|
class WebhookAttempt extends Model
|
||||||
{
|
{
|
||||||
|
@ -170,6 +170,7 @@
|
|||||||
"@php artisan firefly-iii:rename-account-meta",
|
"@php artisan firefly-iii:rename-account-meta",
|
||||||
"@php artisan firefly-iii:migrate-recurrence-meta",
|
"@php artisan firefly-iii:migrate-recurrence-meta",
|
||||||
"@php artisan firefly-iii:migrate-tag-locations",
|
"@php artisan firefly-iii:migrate-tag-locations",
|
||||||
|
"@php artisan firefly-iii:migrate-recurrence-type",
|
||||||
|
|
||||||
"@php artisan firefly-iii:fix-piggies",
|
"@php artisan firefly-iii:fix-piggies",
|
||||||
"@php artisan firefly-iii:create-link-types",
|
"@php artisan firefly-iii:create-link-types",
|
||||||
|
147
composer.lock
generated
147
composer.lock
generated
@ -1356,16 +1356,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzlehttp/promises",
|
"name": "guzzlehttp/promises",
|
||||||
"version": "1.4.0",
|
"version": "1.4.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/guzzle/promises.git",
|
"url": "https://github.com/guzzle/promises.git",
|
||||||
"reference": "60d379c243457e073cff02bc323a2a86cb355631"
|
"reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/guzzle/promises/zipball/60d379c243457e073cff02bc323a2a86cb355631",
|
"url": "https://api.github.com/repos/guzzle/promises/zipball/8e7d04f1f6450fef59366c399cfad4b9383aa30d",
|
||||||
"reference": "60d379c243457e073cff02bc323a2a86cb355631",
|
"reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -1405,9 +1405,9 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/guzzle/promises/issues",
|
"issues": "https://github.com/guzzle/promises/issues",
|
||||||
"source": "https://github.com/guzzle/promises/tree/1.4.0"
|
"source": "https://github.com/guzzle/promises/tree/1.4.1"
|
||||||
},
|
},
|
||||||
"time": "2020-09-30T07:37:28+00:00"
|
"time": "2021-03-07T09:25:29+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzlehttp/psr7",
|
"name": "guzzlehttp/psr7",
|
||||||
@ -1641,16 +1641,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/framework",
|
"name": "laravel/framework",
|
||||||
"version": "v8.31.0",
|
"version": "v8.32.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/laravel/framework.git",
|
"url": "https://github.com/laravel/framework.git",
|
||||||
"reference": "2aa5c2488d25178ebc097052c7897a0e463ddc35"
|
"reference": "7c37b64f8153c16b6406f5c28cf37828ebbe8846"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/laravel/framework/zipball/2aa5c2488d25178ebc097052c7897a0e463ddc35",
|
"url": "https://api.github.com/repos/laravel/framework/zipball/7c37b64f8153c16b6406f5c28cf37828ebbe8846",
|
||||||
"reference": "2aa5c2488d25178ebc097052c7897a0e463ddc35",
|
"reference": "7c37b64f8153c16b6406f5c28cf37828ebbe8846",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -1805,7 +1805,7 @@
|
|||||||
"issues": "https://github.com/laravel/framework/issues",
|
"issues": "https://github.com/laravel/framework/issues",
|
||||||
"source": "https://github.com/laravel/framework"
|
"source": "https://github.com/laravel/framework"
|
||||||
},
|
},
|
||||||
"time": "2021-03-04T15:22:36+00:00"
|
"time": "2021-03-09T15:37:45+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/passport",
|
"name": "laravel/passport",
|
||||||
@ -2792,16 +2792,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "nesbot/carbon",
|
"name": "nesbot/carbon",
|
||||||
"version": "2.45.1",
|
"version": "2.46.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/briannesbitt/Carbon.git",
|
"url": "https://github.com/briannesbitt/Carbon.git",
|
||||||
"reference": "528783b188bdb853eb21239b1722831e0f000a8d"
|
"reference": "2fd2c4a77d58a4e95234c8a61c5df1f157a91bf4"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/528783b188bdb853eb21239b1722831e0f000a8d",
|
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/2fd2c4a77d58a4e95234c8a61c5df1f157a91bf4",
|
||||||
"reference": "528783b188bdb853eb21239b1722831e0f000a8d",
|
"reference": "2fd2c4a77d58a4e95234c8a61c5df1f157a91bf4",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -2881,7 +2881,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-02-11T18:30:17+00:00"
|
"time": "2021-02-24T17:30:44+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "nyholm/psr7",
|
"name": "nyholm/psr7",
|
||||||
@ -4287,20 +4287,20 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "swiftmailer/swiftmailer",
|
"name": "swiftmailer/swiftmailer",
|
||||||
"version": "v6.2.6",
|
"version": "v6.2.7",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/swiftmailer/swiftmailer.git",
|
"url": "https://github.com/swiftmailer/swiftmailer.git",
|
||||||
"reference": "d2791ff0b73247cdc2096b14f5580aba40c12bff"
|
"reference": "15f7faf8508e04471f666633addacf54c0ab5933"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/d2791ff0b73247cdc2096b14f5580aba40c12bff",
|
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/15f7faf8508e04471f666633addacf54c0ab5933",
|
||||||
"reference": "d2791ff0b73247cdc2096b14f5580aba40c12bff",
|
"reference": "15f7faf8508e04471f666633addacf54c0ab5933",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"egulias/email-validator": "^2.0",
|
"egulias/email-validator": "^2.0|^3.1",
|
||||||
"php": ">=7.0.0",
|
"php": ">=7.0.0",
|
||||||
"symfony/polyfill-iconv": "^1.0",
|
"symfony/polyfill-iconv": "^1.0",
|
||||||
"symfony/polyfill-intl-idn": "^1.10",
|
"symfony/polyfill-intl-idn": "^1.10",
|
||||||
@ -4346,7 +4346,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/swiftmailer/swiftmailer/issues",
|
"issues": "https://github.com/swiftmailer/swiftmailer/issues",
|
||||||
"source": "https://github.com/swiftmailer/swiftmailer/tree/v6.2.6"
|
"source": "https://github.com/swiftmailer/swiftmailer/tree/v6.2.7"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -4358,20 +4358,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-03-05T12:08:49+00:00"
|
"time": "2021-03-09T12:30:35+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/console",
|
"name": "symfony/console",
|
||||||
"version": "v5.2.4",
|
"version": "v5.2.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/console.git",
|
"url": "https://github.com/symfony/console.git",
|
||||||
"reference": "d6d0cc30d8c0fda4e7b213c20509b0159a8f4556"
|
"reference": "938ebbadae1b0a9c9d1ec313f87f9708609f1b79"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/console/zipball/d6d0cc30d8c0fda4e7b213c20509b0159a8f4556",
|
"url": "https://api.github.com/repos/symfony/console/zipball/938ebbadae1b0a9c9d1ec313f87f9708609f1b79",
|
||||||
"reference": "d6d0cc30d8c0fda4e7b213c20509b0159a8f4556",
|
"reference": "938ebbadae1b0a9c9d1ec313f87f9708609f1b79",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -4439,7 +4439,7 @@
|
|||||||
"terminal"
|
"terminal"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/console/tree/v5.2.4"
|
"source": "https://github.com/symfony/console/tree/v5.2.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -4455,7 +4455,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-02-23T10:08:49+00:00"
|
"time": "2021-03-06T13:42:15+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/css-selector",
|
"name": "symfony/css-selector",
|
||||||
@ -5037,16 +5037,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/http-kernel",
|
"name": "symfony/http-kernel",
|
||||||
"version": "v5.2.4",
|
"version": "v5.2.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/http-kernel.git",
|
"url": "https://github.com/symfony/http-kernel.git",
|
||||||
"reference": "c452dbe4f385f030c3957821bf921b13815d6140"
|
"reference": "b8c63ef63c2364e174c3b3e0ba0bf83455f97f73"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/c452dbe4f385f030c3957821bf921b13815d6140",
|
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/b8c63ef63c2364e174c3b3e0ba0bf83455f97f73",
|
||||||
"reference": "c452dbe4f385f030c3957821bf921b13815d6140",
|
"reference": "b8c63ef63c2364e174c3b3e0ba0bf83455f97f73",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -5129,7 +5129,7 @@
|
|||||||
"description": "Provides a structured process for converting a Request into a Response",
|
"description": "Provides a structured process for converting a Request into a Response",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/http-kernel/tree/v5.2.4"
|
"source": "https://github.com/symfony/http-kernel/tree/v5.2.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -5145,20 +5145,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-03-04T18:05:55+00:00"
|
"time": "2021-03-10T17:07:35+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/mime",
|
"name": "symfony/mime",
|
||||||
"version": "v5.2.4",
|
"version": "v5.2.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/mime.git",
|
"url": "https://github.com/symfony/mime.git",
|
||||||
"reference": "5155d2fe14ef1eb150e3bdbbc1ec1455df95e9cd"
|
"reference": "554ba128f1955038b45db5e1fa7e93bfc683b139"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/mime/zipball/5155d2fe14ef1eb150e3bdbbc1ec1455df95e9cd",
|
"url": "https://api.github.com/repos/symfony/mime/zipball/554ba128f1955038b45db5e1fa7e93bfc683b139",
|
||||||
"reference": "5155d2fe14ef1eb150e3bdbbc1ec1455df95e9cd",
|
"reference": "554ba128f1955038b45db5e1fa7e93bfc683b139",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -5169,12 +5169,13 @@
|
|||||||
"symfony/polyfill-php80": "^1.15"
|
"symfony/polyfill-php80": "^1.15"
|
||||||
},
|
},
|
||||||
"conflict": {
|
"conflict": {
|
||||||
|
"egulias/email-validator": "~3.0.0",
|
||||||
"phpdocumentor/reflection-docblock": "<3.2.2",
|
"phpdocumentor/reflection-docblock": "<3.2.2",
|
||||||
"phpdocumentor/type-resolver": "<1.4.0",
|
"phpdocumentor/type-resolver": "<1.4.0",
|
||||||
"symfony/mailer": "<4.4"
|
"symfony/mailer": "<4.4"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"egulias/email-validator": "^2.1.10",
|
"egulias/email-validator": "^2.1.10|^3.1",
|
||||||
"phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
|
"phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
|
||||||
"symfony/dependency-injection": "^4.4|^5.0",
|
"symfony/dependency-injection": "^4.4|^5.0",
|
||||||
"symfony/property-access": "^4.4|^5.1",
|
"symfony/property-access": "^4.4|^5.1",
|
||||||
@ -5211,7 +5212,7 @@
|
|||||||
"mime-type"
|
"mime-type"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/mime/tree/v5.2.4"
|
"source": "https://github.com/symfony/mime/tree/v5.2.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -5227,7 +5228,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-02-15T18:55:04+00:00"
|
"time": "2021-03-07T16:08:20+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-ctype",
|
"name": "symfony/polyfill-ctype",
|
||||||
@ -6362,16 +6363,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/translation",
|
"name": "symfony/translation",
|
||||||
"version": "v5.2.4",
|
"version": "v5.2.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/translation.git",
|
"url": "https://github.com/symfony/translation.git",
|
||||||
"reference": "74b0353ab34ff4cca827a2cf909e325d96815e60"
|
"reference": "0947ab1e3aabd22a6bef393874b2555d2bb976da"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/translation/zipball/74b0353ab34ff4cca827a2cf909e325d96815e60",
|
"url": "https://api.github.com/repos/symfony/translation/zipball/0947ab1e3aabd22a6bef393874b2555d2bb976da",
|
||||||
"reference": "74b0353ab34ff4cca827a2cf909e325d96815e60",
|
"reference": "0947ab1e3aabd22a6bef393874b2555d2bb976da",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -6435,7 +6436,7 @@
|
|||||||
"description": "Provides tools to internationalize your application",
|
"description": "Provides tools to internationalize your application",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/translation/tree/v5.2.4"
|
"source": "https://github.com/symfony/translation/tree/v5.2.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -6451,7 +6452,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-03-04T15:41:09+00:00"
|
"time": "2021-03-06T07:59:01+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/translation-contracts",
|
"name": "symfony/translation-contracts",
|
||||||
@ -6533,16 +6534,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/var-dumper",
|
"name": "symfony/var-dumper",
|
||||||
"version": "v5.2.4",
|
"version": "v5.2.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/var-dumper.git",
|
"url": "https://github.com/symfony/var-dumper.git",
|
||||||
"reference": "6a81fec0628c468cf6d5c87a4d003725e040e223"
|
"reference": "002ab5a36702adf0c9a11e6d8836623253e9045e"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/6a81fec0628c468cf6d5c87a4d003725e040e223",
|
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/002ab5a36702adf0c9a11e6d8836623253e9045e",
|
||||||
"reference": "6a81fec0628c468cf6d5c87a4d003725e040e223",
|
"reference": "002ab5a36702adf0c9a11e6d8836623253e9045e",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -6601,7 +6602,7 @@
|
|||||||
"dump"
|
"dump"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/var-dumper/tree/v5.2.4"
|
"source": "https://github.com/symfony/var-dumper/tree/v5.2.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -6617,7 +6618,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-02-18T23:11:19+00:00"
|
"time": "2021-03-06T07:59:01+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "tijsverkoyen/css-to-inline-styles",
|
"name": "tijsverkoyen/css-to-inline-styles",
|
||||||
@ -6674,16 +6675,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "twig/twig",
|
"name": "twig/twig",
|
||||||
"version": "v2.14.3",
|
"version": "v2.14.4",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/twigphp/Twig.git",
|
"url": "https://github.com/twigphp/Twig.git",
|
||||||
"reference": "8bc568d460d88b25c00c046256ec14a787ea60d9"
|
"reference": "0b4ba691fb99ec7952d25deb36c0a83061b93bbf"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/8bc568d460d88b25c00c046256ec14a787ea60d9",
|
"url": "https://api.github.com/repos/twigphp/Twig/zipball/0b4ba691fb99ec7952d25deb36c0a83061b93bbf",
|
||||||
"reference": "8bc568d460d88b25c00c046256ec14a787ea60d9",
|
"reference": "0b4ba691fb99ec7952d25deb36c0a83061b93bbf",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -6737,7 +6738,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/twigphp/Twig/issues",
|
"issues": "https://github.com/twigphp/Twig/issues",
|
||||||
"source": "https://github.com/twigphp/Twig/tree/v2.14.3"
|
"source": "https://github.com/twigphp/Twig/tree/v2.14.4"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -6749,7 +6750,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-01-05T15:34:33+00:00"
|
"time": "2021-03-10T10:05:55+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "vlucas/phpdotenv",
|
"name": "vlucas/phpdotenv",
|
||||||
@ -9105,16 +9106,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpstan/phpstan",
|
"name": "phpstan/phpstan",
|
||||||
"version": "0.12.80",
|
"version": "0.12.81",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/phpstan/phpstan.git",
|
"url": "https://github.com/phpstan/phpstan.git",
|
||||||
"reference": "c6a1b17f22ecf708d434d6bee05092647ec7e686"
|
"reference": "0dd5b0ebeff568f7000022ea5f04aa86ad3124b8"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/c6a1b17f22ecf708d434d6bee05092647ec7e686",
|
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/0dd5b0ebeff568f7000022ea5f04aa86ad3124b8",
|
||||||
"reference": "c6a1b17f22ecf708d434d6bee05092647ec7e686",
|
"reference": "0dd5b0ebeff568f7000022ea5f04aa86ad3124b8",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -9145,7 +9146,7 @@
|
|||||||
"description": "PHPStan - PHP Static Analysis Tool",
|
"description": "PHPStan - PHP Static Analysis Tool",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/phpstan/phpstan/issues",
|
"issues": "https://github.com/phpstan/phpstan/issues",
|
||||||
"source": "https://github.com/phpstan/phpstan/tree/0.12.80"
|
"source": "https://github.com/phpstan/phpstan/tree/0.12.81"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -9161,7 +9162,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-02-28T20:22:43+00:00"
|
"time": "2021-03-08T22:03:02+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpstan/phpstan-deprecation-rules",
|
"name": "phpstan/phpstan-deprecation-rules",
|
||||||
@ -9691,12 +9692,12 @@
|
|||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/Roave/SecurityAdvisories.git",
|
"url": "https://github.com/Roave/SecurityAdvisories.git",
|
||||||
"reference": "0745f820eed6cb92603ca44a9c137ff8ce315e86"
|
"reference": "672ed7cb0191a12cf8b12b752c9ef74bb5d21cec"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/0745f820eed6cb92603ca44a9c137ff8ce315e86",
|
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/672ed7cb0191a12cf8b12b752c9ef74bb5d21cec",
|
||||||
"reference": "0745f820eed6cb92603ca44a9c137ff8ce315e86",
|
"reference": "672ed7cb0191a12cf8b12b752c9ef74bb5d21cec",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"conflict": {
|
"conflict": {
|
||||||
@ -9756,8 +9757,9 @@
|
|||||||
"ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.6",
|
"ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.6",
|
||||||
"ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2.1|>=5,<5.0.1|>=5.1,<5.1.1",
|
"ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2.1|>=5,<5.0.1|>=5.1,<5.1.1",
|
||||||
"ezsystems/ezplatform-kernel": ">=1,<1.0.2.1",
|
"ezsystems/ezplatform-kernel": ">=1,<1.0.2.1",
|
||||||
|
"ezsystems/ezplatform-rest": ">=1.2,<=1.2.2|>=1.3,<=1.3.1",
|
||||||
"ezsystems/ezplatform-user": ">=1,<1.0.1",
|
"ezsystems/ezplatform-user": ">=1,<1.0.1",
|
||||||
"ezsystems/ezpublish-kernel": ">=5.3,<5.3.12.1|>=5.4,<5.4.14.2|>=6,<6.7.9.1|>=6.8,<6.13.6.3|>=7,<7.2.4.1|>=7.3,<7.3.2.1|>=7.5,<7.5.7.1",
|
"ezsystems/ezpublish-kernel": ">=5.3,<5.3.12.1|>=5.4,<5.4.14.2|>=6,<6.7.9.1|>=6.8,<=6.13.8|>=7,<7.2.4.1|>=7.3,<7.3.2.1|>=7.5,<=7.5.15",
|
||||||
"ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.14.2|>=2011,<2017.12.7.3|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3|>=2019.3,<2019.3.5.1",
|
"ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.14.2|>=2011,<2017.12.7.3|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3|>=2019.3,<2019.3.5.1",
|
||||||
"ezsystems/platform-ui-assets-bundle": ">=4.2,<4.2.3",
|
"ezsystems/platform-ui-assets-bundle": ">=4.2,<4.2.3",
|
||||||
"ezsystems/repository-forms": ">=2.3,<2.3.2.1",
|
"ezsystems/repository-forms": ">=2.3,<2.3.2.1",
|
||||||
@ -9787,6 +9789,7 @@
|
|||||||
"illuminate/view": ">=7,<7.1.2",
|
"illuminate/view": ">=7,<7.1.2",
|
||||||
"ivankristianto/phpwhois": "<=4.3",
|
"ivankristianto/phpwhois": "<=4.3",
|
||||||
"james-heinrich/getid3": "<1.9.9",
|
"james-heinrich/getid3": "<1.9.9",
|
||||||
|
"joomla/archive": "<1.1.10",
|
||||||
"joomla/session": "<1.3.1",
|
"joomla/session": "<1.3.1",
|
||||||
"jsmitty12/phpwhois": "<5.1",
|
"jsmitty12/phpwhois": "<5.1",
|
||||||
"kazist/phpwhois": "<=4.2.6",
|
"kazist/phpwhois": "<=4.2.6",
|
||||||
@ -9812,7 +9815,7 @@
|
|||||||
"nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13",
|
"nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13",
|
||||||
"nystudio107/craft-seomatic": "<3.3",
|
"nystudio107/craft-seomatic": "<3.3",
|
||||||
"nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1",
|
"nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1",
|
||||||
"october/backend": ">=1.0.319,<1.0.470",
|
"october/backend": "<1.1.2",
|
||||||
"october/cms": "= 1.0.469|>=1.0.319,<1.0.469",
|
"october/cms": "= 1.0.469|>=1.0.319,<1.0.469",
|
||||||
"october/october": ">=1.0.319,<1.0.466",
|
"october/october": ">=1.0.319,<1.0.466",
|
||||||
"october/rain": "<1.0.472|>=1.1,<1.1.2",
|
"october/rain": "<1.0.472|>=1.1,<1.1.2",
|
||||||
@ -10011,7 +10014,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-03-03T23:02:20+00:00"
|
"time": "2021-03-11T18:09:51+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/cli-parser",
|
"name": "sebastian/cli-parser",
|
||||||
|
Loading…
Reference in New Issue
Block a user