Fix a few commands.

This commit is contained in:
James Cole
2023-05-07 20:17:29 +02:00
parent 309d3e8e95
commit e5a77a86f9
33 changed files with 1575 additions and 1017 deletions

View File

@@ -96,20 +96,6 @@ class AccountCurrencies extends Command
return 0;
}
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
*/
private function stupidLaravel(): void
{
$this->accountRepos = app(AccountRepositoryInterface::class);
$this->userRepos = app(UserRepositoryInterface::class);
$this->count = 0;
}
/**
* @return bool
* @throws ContainerExceptionInterface
@@ -128,50 +114,23 @@ class AccountCurrencies extends Command
/**
*
*/
private function updateAccountCurrencies(): void
private function markAsExecuted(): void
{
Log::debug('Now in updateAccountCurrencies()');
$users = $this->userRepos->all();
$defaultCurrencyCode = (string)config('firefly.default_currency', 'EUR');
Log::debug(sprintf('Default currency is %s', $defaultCurrencyCode));
foreach ($users as $user) {
$this->updateCurrenciesForUser($user, $defaultCurrencyCode);
}
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
/**
* @param User $user
* @param string $systemCurrencyCode
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
* @throws FireflyException
*/
private function updateCurrenciesForUser(User $user, string $systemCurrencyCode): void
private function stupidLaravel(): 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|null $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);
}
$this->accountRepos = app(AccountRepositoryInterface::class);
$this->userRepos = app(UserRepositoryInterface::class);
$this->count = 0;
}
/**
@@ -237,8 +196,49 @@ class AccountCurrencies extends Command
/**
*
*/
private function markAsExecuted(): void
private function updateAccountCurrencies(): void
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
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
*
* @throws FireflyException
*/
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|null $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);
}
}
}

View File

@@ -73,30 +73,6 @@ class AppendBudgetLimitPeriods extends Command
return 0;
}
/**
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function isExecuted(): bool
{
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
return (bool)$configVar->data;
}
/**
*
*/
private function theresNoLimit(): void
{
$limits = BudgetLimit::whereNull('period')->get();
/** @var BudgetLimit $limit */
foreach ($limits as $limit) {
$this->fixLimit($limit);
}
}
/**
* @param BudgetLimit $limit
*/
@@ -182,6 +158,18 @@ class AppendBudgetLimitPeriods extends Command
return null;
}
/**
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function isExecuted(): bool
{
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
return (bool)$configVar->data;
}
/**
*
*/
@@ -189,4 +177,16 @@ class AppendBudgetLimitPeriods extends Command
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
/**
*
*/
private function theresNoLimit(): void
{
$limits = BudgetLimit::whereNull('period')->get();
/** @var BudgetLimit $limit */
foreach ($limits as $limit) {
$this->fixLimit($limit);
}
}
}

View File

@@ -87,15 +87,39 @@ class BackToJournals extends Command
}
/**
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @return array
*/
private function isMigrated(): bool
private function getIdsForBudgets(): array
{
$configVar = app('fireflyconfig')->get(MigrateToGroups::CONFIG_NAME, false);
$transactions = DB::table('budget_transaction')->distinct()->pluck('transaction_id')->toArray();
$array = [];
$chunks = array_chunk($transactions, 500);
return (bool)$configVar->data;
foreach ($chunks as $chunk) {
$set = DB::table('transactions')->whereIn('transactions.id', $chunk)->pluck('transaction_journal_id')->toArray();
$array = array_merge($array, $set);
}
return $array;
}
/**
* @return array
*/
private function getIdsForCategories(): array
{
$transactions = DB::table('category_transaction')->distinct()->pluck('transaction_id')->toArray();
$array = [];
$chunks = array_chunk($transactions, 500);
foreach ($chunks as $chunk) {
$set = DB::table('transactions')
->whereIn('transactions.id', $chunk)
->pluck('transaction_journal_id')->toArray();
$array = array_merge($array, $set);
}
return $array;
}
/**
@@ -110,6 +134,26 @@ class BackToJournals extends Command
return (bool)$configVar->data;
}
/**
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function isMigrated(): bool
{
$configVar = app('fireflyconfig')->get(MigrateToGroups::CONFIG_NAME, false);
return (bool)$configVar->data;
}
/**
*
*/
private function markAsExecuted(): void
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
/**
*
*/
@@ -143,23 +187,6 @@ class BackToJournals extends Command
}
}
/**
* @return array
*/
private function getIdsForBudgets(): array
{
$transactions = DB::table('budget_transaction')->distinct()->pluck('transaction_id')->toArray();
$array = [];
$chunks = array_chunk($transactions, 500);
foreach ($chunks as $chunk) {
$set = DB::table('transactions')->whereIn('transactions.id', $chunk)->pluck('transaction_journal_id')->toArray();
$array = array_merge($array, $set);
}
return $array;
}
/**
* @param TransactionJournal $journal
*/
@@ -217,25 +244,6 @@ class BackToJournals extends Command
}
}
/**
* @return array
*/
private function getIdsForCategories(): array
{
$transactions = DB::table('category_transaction')->distinct()->pluck('transaction_id')->toArray();
$array = [];
$chunks = array_chunk($transactions, 500);
foreach ($chunks as $chunk) {
$set = DB::table('transactions')
->whereIn('transactions.id', $chunk)
->pluck('transaction_journal_id')->toArray();
$array = array_merge($array, $set);
}
return $array;
}
/**
* @param TransactionJournal $journal
*/
@@ -265,12 +273,4 @@ class BackToJournals extends Command
$journal->categories()->sync([(int)$category->id]);
}
}
/**
*
*/
private function markAsExecuted(): void
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
}

View File

@@ -87,6 +87,81 @@ class DecryptDatabase extends Command
return 0;
}
/**
* @param string $table
* @param string $field
*/
private function decryptField(string $table, string $field): void
{
$rows = DB::table($table)->get(['id', $field]);
/** @var stdClass $row */
foreach ($rows as $row) {
$this->decryptRow($table, $field, $row);
}
}
/**
* @param int $id
* @param string $value
*/
private function decryptPreferencesRow(int $id, string $value): void
{
// try to json_decrypt the value.
try {
$newValue = json_decode($value, true, 512, JSON_THROW_ON_ERROR) ?? $value;
} catch (JsonException $e) {
$message = sprintf('Could not JSON decode preference row #%d: %s. This does not have to be a problem.', $id, $e->getMessage());
$this->error($message);
app('log')->warning($message);
app('log')->warning($value);
app('log')->warning($e->getTraceAsString());
return;
}
/** @var Preference $object */
$object = Preference::find((int)$id);
if (null !== $object) {
$object->data = $newValue;
$object->save();
}
}
/**
* @param string $table
* @param string $field
* @param stdClass $row
*/
private function decryptRow(string $table, string $field, stdClass $row): void
{
$original = $row->$field;
if (null === $original) {
return;
}
$id = (int)$row->id;
$value = '';
try {
$value = $this->tryDecrypt($original);
} catch (FireflyException $e) {
$message = sprintf('Could not decrypt field "%s" in row #%d of table "%s": %s', $field, $id, $table, $e->getMessage());
$this->error($message);
Log::error($message);
Log::error($e->getTraceAsString());
}
// A separate routine for preferences table:
if ('preferences' === $table) {
$this->decryptPreferencesRow($id, $value);
return;
}
if ($value !== $original) {
DB::table($table)->where('id', $id)->update([$field => $value]);
}
}
/**
* @param string $table
* @param array $fields
@@ -132,54 +207,6 @@ class DecryptDatabase extends Command
return false;
}
/**
* @param string $table
* @param string $field
*/
private function decryptField(string $table, string $field): void
{
$rows = DB::table($table)->get(['id', $field]);
/** @var stdClass $row */
foreach ($rows as $row) {
$this->decryptRow($table, $field, $row);
}
}
/**
* @param string $table
* @param string $field
* @param stdClass $row
*/
private function decryptRow(string $table, string $field, stdClass $row): void
{
$original = $row->$field;
if (null === $original) {
return;
}
$id = (int)$row->id;
$value = '';
try {
$value = $this->tryDecrypt($original);
} catch (FireflyException $e) {
$message = sprintf('Could not decrypt field "%s" in row #%d of table "%s": %s', $field, $id, $table, $e->getMessage());
$this->error($message);
Log::error($message);
Log::error($e->getTraceAsString());
}
// A separate routine for preferences table:
if ('preferences' === $table) {
$this->decryptPreferencesRow($id, $value);
return;
}
if ($value !== $original) {
DB::table($table)->where('id', $id)->update([$field => $value]);
}
}
/**
* Tries to decrypt data. Will only throw an exception when the MAC is invalid.
*
@@ -200,31 +227,4 @@ class DecryptDatabase extends Command
return $value;
}
/**
* @param int $id
* @param string $value
*/
private function decryptPreferencesRow(int $id, string $value): void
{
// try to json_decrypt the value.
try {
$newValue = json_decode($value, true, 512, JSON_THROW_ON_ERROR) ?? $value;
} catch (JsonException $e) {
$message = sprintf('Could not JSON decode preference row #%d: %s. This does not have to be a problem.', $id, $e->getMessage());
$this->error($message);
app('log')->warning($message);
app('log')->warning($value);
app('log')->warning($e->getTraceAsString());
return;
}
/** @var Preference $object */
$object = Preference::find((int)$id);
if (null !== $object) {
$object->data = $newValue;
$object->save();
}
}
}

View File

@@ -102,20 +102,11 @@ class MigrateRecurrenceMeta extends Command
}
/**
* @return int
* @throws JsonException
*
*/
private function migrateMetaData(): int
private function markAsExecuted(): void
{
$count = 0;
// get all recurrence meta data:
$collection = RecurrenceMeta::with('recurrence')->get();
/** @var RecurrenceMeta $meta */
foreach ($collection as $meta) {
$count += $this->migrateEntry($meta);
}
return $count;
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
/**
@@ -155,10 +146,19 @@ class MigrateRecurrenceMeta extends Command
}
/**
*
* @return int
* @throws JsonException
*/
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;
}
}

View File

@@ -78,6 +78,14 @@ class MigrateRecurrenceType extends Command
return 0;
}
/**
*
*/
private function getInvalidType(): TransactionType
{
return TransactionType::whereType(TransactionType::INVALID)->firstOrCreate(['type' => TransactionType::INVALID]);
}
/**
* @return bool
* @throws ContainerExceptionInterface
@@ -96,15 +104,9 @@ class MigrateRecurrenceType extends Command
/**
*
*/
private function migrateTypes(): void
private function markAsExecuted(): void
{
$set = Recurrence::get();
/** @var Recurrence $recurrence */
foreach ($set as $recurrence) {
if ($recurrence->transactionType->type !== TransactionType::INVALID) {
$this->migrateRecurrence($recurrence);
}
}
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
private function migrateRecurrence(Recurrence $recurrence): void
@@ -124,16 +126,14 @@ class MigrateRecurrenceType extends Command
/**
*
*/
private function getInvalidType(): TransactionType
private function migrateTypes(): void
{
return TransactionType::whereType(TransactionType::INVALID)->firstOrCreate(['type' => TransactionType::INVALID]);
}
/**
*
*/
private function markAsExecuted(): void
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
$set = Recurrence::get();
/** @var Recurrence $recurrence */
foreach ($set as $recurrence) {
if ($recurrence->transactionType->type !== TransactionType::INVALID) {
$this->migrateRecurrence($recurrence);
}
}
}
}

View File

@@ -75,6 +75,16 @@ class MigrateTagLocations extends Command
return 0;
}
/**
* @param Tag $tag
*
* @return bool
*/
private function hasLocationDetails(Tag $tag): bool
{
return null !== $tag->latitude && null !== $tag->longitude && null !== $tag->zoomLevel;
}
/**
* @return bool
* @throws ContainerExceptionInterface
@@ -90,25 +100,12 @@ class MigrateTagLocations extends Command
return false;
}
private function migrateTagLocations(): void
{
$tags = Tag::get();
/** @var Tag $tag */
foreach ($tags as $tag) {
if ($this->hasLocationDetails($tag)) {
$this->migrateLocationDetails($tag);
}
}
}
/**
* @param Tag $tag
*
* @return bool
*/
private function hasLocationDetails(Tag $tag): bool
private function markAsExecuted(): void
{
return null !== $tag->latitude && null !== $tag->longitude && null !== $tag->zoomLevel;
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
/**
@@ -129,11 +126,14 @@ class MigrateTagLocations extends Command
$tag->save();
}
/**
*
*/
private function markAsExecuted(): void
private function migrateTagLocations(): void
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
$tags = Tag::get();
/** @var Tag $tag */
foreach ($tags as $tag) {
if ($this->hasLocationDetails($tag)) {
$this->migrateLocationDetails($tag);
}
}
}
}

View File

@@ -105,22 +105,6 @@ class MigrateToRules extends Command
return 0;
}
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
*/
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
* @throws ContainerExceptionInterface
@@ -137,38 +121,11 @@ class MigrateToRules extends Command
}
/**
* Migrate bills to new rule structure for a specific user.
*
* @param User $user
*
* @throws FireflyException
*/
private function migrateUser(User $user): void
private function markAsExecuted(): void
{
$this->ruleGroupRepository->setUser($user);
$this->billRepository->setUser($user);
$this->ruleRepository->setUser($user);
/** @var Preference $lang */
$lang = app('preferences')->getForUser($user, 'language', 'en_US');
$groupTitle = (string)trans('firefly.rulegroup_for_bills_title', [], $lang->data);
$ruleGroup = $this->ruleGroupRepository->findByTitle($groupTitle);
if (null === $ruleGroup) {
$ruleGroup = $this->ruleGroupRepository->store(
[
'title' => (string)trans('firefly.rulegroup_for_bills_title', [], $lang->data),
'description' => (string)trans('firefly.rulegroup_for_bills_description', [], $lang->data),
'active' => true,
]
);
}
$bills = $this->billRepository->getBills();
/** @var Bill $bill */
foreach ($bills as $bill) {
$this->migrateBill($ruleGroup, $bill, $lang);
}
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
/**
@@ -243,10 +200,53 @@ class MigrateToRules extends Command
}
/**
* 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);
}
}
/**
* 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.
*
*/
private function stupidLaravel(): void
{
$this->count = 0;
$this->userRepository = app(UserRepositoryInterface::class);
$this->ruleGroupRepository = app(RuleGroupRepositoryInterface::class);
$this->billRepository = app(BillRepositoryInterface::class);
$this->ruleRepository = app(RuleRepositoryInterface::class);
}
}

View File

@@ -107,63 +107,6 @@ class TransactionIdentifier extends Command
return 0;
}
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
*/
private function stupidLaravel(): void
{
$this->cliRepository = app(JournalCLIRepositoryInterface::class);
$this->count = 0;
}
/**
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function isExecuted(): bool
{
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
if (null !== $configVar) {
return (bool)$configVar->data;
}
return false;
}
/**
* 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.
*
* @param TransactionJournal $transactionJournal
*/
private function updateJournalIdentifiers(TransactionJournal $transactionJournal): void
{
$identifier = 0;
$exclude = []; // transactions already processed.
$transactions = $transactionJournal->transactions()->where('amount', '>', 0)->get();
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
$opposing = $this->findOpposing($transaction, $exclude);
if (null !== $opposing) {
// give both a new identifier:
$transaction->identifier = $identifier;
$opposing->identifier = $identifier;
$transaction->save();
$opposing->save();
$exclude[] = $transaction->id;
$exclude[] = $opposing->id;
$this->count++;
}
++$identifier;
}
}
/**
* @param Transaction $transaction
* @param array $exclude
@@ -194,6 +137,21 @@ class TransactionIdentifier extends Command
return $opposing;
}
/**
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function isExecuted(): bool
{
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
if (null !== $configVar) {
return (bool)$configVar->data;
}
return false;
}
/**
*
*/
@@ -201,4 +159,46 @@ class TransactionIdentifier extends Command
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
*/
private function stupidLaravel(): void
{
$this->cliRepository = app(JournalCLIRepositoryInterface::class);
$this->count = 0;
}
/**
* Grab all positive transactions from this journal that are not deleted. for each one, grab the negative opposing one
* which has 0 as an identifier and give it the same identifier.
*
* @param TransactionJournal $transactionJournal
*/
private function updateJournalIdentifiers(TransactionJournal $transactionJournal): void
{
$identifier = 0;
$exclude = []; // transactions already processed.
$transactions = $transactionJournal->transactions()->where('amount', '>', 0)->get();
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
$opposing = $this->findOpposing($transaction, $exclude);
if (null !== $opposing) {
// give both a new identifier:
$transaction->identifier = $identifier;
$opposing->identifier = $identifier;
$transaction->save();
$opposing->save();
$exclude[] = $transaction->id;
$exclude[] = $opposing->id;
$this->count++;
}
++$identifier;
}
}
}

View File

@@ -98,7 +98,7 @@ class UpgradeDatabase extends Command
private function callInitialCommands(): void
{
$this->line('Now seeding the database...');
$this->call('migrate', ['--seed' => true, '--force' => true,'--no-interaction' => true]);
$this->call('migrate', ['--seed' => true, '--force' => true, '--no-interaction' => true]);
$this->line('Fix PostgreSQL sequences.');
$this->call('firefly-iii:fix-pgsql-sequences');

View File

@@ -82,79 +82,6 @@ class UpgradeLiabilities extends Command
return 0;
}
/**
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function isExecuted(): bool
{
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
if (null !== $configVar) {
return (bool)$configVar->data;
}
return false;
}
/**
*
*/
private function upgradeLiabilities(): void
{
Log::debug('Upgrading liabilities.');
$users = User::get();
/** @var User $user */
foreach ($users as $user) {
$this->upgradeForUser($user);
}
}
/**
* @param User $user
*/
private function upgradeForUser(User $user): void
{
Log::debug(sprintf('Upgrading liabilities for user #%d', $user->id));
$accounts = $user->accounts()
->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->whereIn('account_types.type', config('firefly.valid_liabilities'))
->get(['accounts.*']);
/** @var Account $account */
foreach ($accounts as $account) {
$this->upgradeLiability($account);
$service = app(CreditRecalculateService::class);
$service->setAccount($account);
$service->recalculate();
}
}
/**
* @param Account $account
*/
private function upgradeLiability(Account $account): void
{
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$repository->setUser($account->user);
Log::debug(sprintf('Upgrade liability #%d', $account->id));
// get opening balance, and correct if necessary.
$openingBalance = $repository->getOpeningBalance($account);
if (null !== $openingBalance) {
// correct if necessary
$this->correctOpeningBalance($account, $openingBalance);
}
// add liability direction property (if it does not yet exist!)
$value = $repository->getMetaValue($account, 'liability_direction');
if (null === $value) {
/** @var AccountMetaFactory $factory */
$factory = app(AccountMetaFactory::class);
$factory->crud($account, 'liability_direction', 'debit');
}
}
/**
* @param Account $account
* @param TransactionJournal $openingBalance
@@ -185,9 +112,9 @@ class UpgradeLiabilities extends Command
*
* @return Transaction|null
*/
private function getSourceTransaction(TransactionJournal $journal): ?Transaction
private function getDestinationTransaction(TransactionJournal $journal): ?Transaction
{
return $journal->transactions()->where('amount', '<', 0)->first();
return $journal->transactions()->where('amount', '>', 0)->first();
}
/**
@@ -195,9 +122,24 @@ class UpgradeLiabilities extends Command
*
* @return Transaction|null
*/
private function getDestinationTransaction(TransactionJournal $journal): ?Transaction
private function getSourceTransaction(TransactionJournal $journal): ?Transaction
{
return $journal->transactions()->where('amount', '>', 0)->first();
return $journal->transactions()->where('amount', '<', 0)->first();
}
/**
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function isExecuted(): bool
{
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
if (null !== $configVar) {
return (bool)$configVar->data;
}
return false;
}
/**
@@ -207,4 +149,62 @@ class UpgradeLiabilities extends Command
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
/**
* @param User $user
*/
private function upgradeForUser(User $user): void
{
Log::debug(sprintf('Upgrading liabilities for user #%d', $user->id));
$accounts = $user->accounts()
->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->whereIn('account_types.type', config('firefly.valid_liabilities'))
->get(['accounts.*']);
/** @var Account $account */
foreach ($accounts as $account) {
$this->upgradeLiability($account);
$service = app(CreditRecalculateService::class);
$service->setAccount($account);
$service->recalculate();
}
}
/**
*
*/
private function upgradeLiabilities(): void
{
Log::debug('Upgrading liabilities.');
$users = User::get();
/** @var User $user */
foreach ($users as $user) {
$this->upgradeForUser($user);
}
}
/**
* @param Account $account
*/
private function upgradeLiability(Account $account): void
{
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$repository->setUser($account->user);
Log::debug(sprintf('Upgrade liability #%d', $account->id));
// get opening balance, and correct if necessary.
$openingBalance = $repository->getOpeningBalance($account);
if (null !== $openingBalance) {
// correct if necessary
$this->correctOpeningBalance($account, $openingBalance);
}
// add liability direction property (if it does not yet exist!)
$value = $repository->getMetaValue($account, 'liability_direction');
if (null === $value) {
/** @var AccountMetaFactory $factory */
$factory = app(AccountMetaFactory::class);
$factory->crud($account, 'liability_direction', 'debit');
}
}
}

View File

@@ -83,115 +83,6 @@ class UpgradeLiabilitiesEight extends Command
return 0;
}
/**
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function isExecuted(): bool
{
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
if (null !== $configVar) {
return (bool)$configVar->data;
}
return false;
}
/**
*
*/
private function upgradeLiabilities(): void
{
Log::debug('Upgrading liabilities.');
$users = User::get();
/** @var User $user */
foreach ($users as $user) {
$this->upgradeForUser($user);
}
}
/**
* @param User $user
*/
private function upgradeForUser(User $user): void
{
Log::debug(sprintf('Upgrading liabilities for user #%d', $user->id));
$accounts = $user->accounts()
->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->whereIn('account_types.type', config('firefly.valid_liabilities'))
->get(['accounts.*']);
/** @var Account $account */
foreach ($accounts as $account) {
$this->upgradeLiability($account);
$service = app(CreditRecalculateService::class);
$service->setAccount($account);
$service->recalculate();
}
}
/**
* @param Account $account
*/
private function upgradeLiability(Account $account): void
{
Log::debug(sprintf('Upgrade liability #%d ("%s")', $account->id, $account->name));
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$repository->setUser($account->user);
$direction = $repository->getMetaValue($account, 'liability_direction');
if ('debit' === $direction) {
Log::debug('Direction is debit ("I owe this amount"), so no need to upgrade.');
}
if ('credit' === $direction && $this->hasBadOpening($account)) {
$this->deleteCreditTransaction($account);
$this->reverseOpeningBalance($account);
$this->line(sprintf('Corrected opening balance for liability #%d ("%s")', $account->id, $account->name));
}
if ('credit' === $direction) {
$count = $this->deleteTransactions($account);
if ($count > 0) {
$this->line(sprintf('Removed %d old format transaction(s) for liability #%d ("%s")', $count, $account->id, $account->name));
}
}
Log::debug(sprintf('Done upgrading liability #%d ("%s")', $account->id, $account->name));
}
/**
* @param Account $account
* @return bool
*/
private function hasBadOpening(Account $account): bool
{
$openingBalanceType = TransactionType::whereType(TransactionType::OPENING_BALANCE)->first();
$liabilityType = TransactionType::whereType(TransactionType::LIABILITY_CREDIT)->first();
$openingJournal = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $account->id)
->where('transaction_journals.transaction_type_id', $openingBalanceType->id)
->first(['transaction_journals.*']);
if (null === $openingJournal) {
Log::debug('Account has no opening balance and can be skipped.');
return false;
}
$liabilityJournal = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $account->id)
->where('transaction_journals.transaction_type_id', $liabilityType->id)
->first(['transaction_journals.*']);
if (null === $liabilityJournal) {
Log::debug('Account has no liability credit and can be skipped.');
return false;
}
if (!$openingJournal->date->isSameDay($liabilityJournal->date)) {
Log::debug('Account has opening/credit not on the same day.');
return false;
}
Log::debug('Account has bad opening balance data.');
return true;
}
/**
* @param Account $account
* @return void
@@ -214,35 +105,6 @@ class UpgradeLiabilitiesEight extends Command
Log::debug('No liability credit journal found.');
}
/**
* @param Account $account
* @return void
*/
private function reverseOpeningBalance(Account $account): void
{
$openingBalanceType = TransactionType::whereType(TransactionType::OPENING_BALANCE)->first();
/** @var TransactionJournal $openingJournal */
$openingJournal = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $account->id)
->where('transaction_journals.transaction_type_id', $openingBalanceType->id)
->first(['transaction_journals.*']);
/** @var Transaction|null $source */
$source = $openingJournal->transactions()->where('amount', '<', 0)->first();
/** @var Transaction|null $dest */
$dest = $openingJournal->transactions()->where('amount', '>', 0)->first();
if ($source && $dest) {
$sourceId = $source->account_id;
$destId = $dest->account_id;
$dest->account_id = $sourceId;
$source->account_id = $destId;
$source->save();
$dest->save();
Log::debug(sprintf('Opening balance transaction journal #%d reversed.', $openingJournal->id));
return;
}
Log::warning('Did not find opening balance.');
}
/**
* @param $account
* @return int
@@ -293,6 +155,54 @@ class UpgradeLiabilitiesEight extends Command
return $count;
}
/**
* @param Account $account
* @return bool
*/
private function hasBadOpening(Account $account): bool
{
$openingBalanceType = TransactionType::whereType(TransactionType::OPENING_BALANCE)->first();
$liabilityType = TransactionType::whereType(TransactionType::LIABILITY_CREDIT)->first();
$openingJournal = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $account->id)
->where('transaction_journals.transaction_type_id', $openingBalanceType->id)
->first(['transaction_journals.*']);
if (null === $openingJournal) {
Log::debug('Account has no opening balance and can be skipped.');
return false;
}
$liabilityJournal = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $account->id)
->where('transaction_journals.transaction_type_id', $liabilityType->id)
->first(['transaction_journals.*']);
if (null === $liabilityJournal) {
Log::debug('Account has no liability credit and can be skipped.');
return false;
}
if (!$openingJournal->date->isSameDay($liabilityJournal->date)) {
Log::debug('Account has opening/credit not on the same day.');
return false;
}
Log::debug('Account has bad opening balance data.');
return true;
}
/**
* @return bool
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function isExecuted(): bool
{
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
if (null !== $configVar) {
return (bool)$configVar->data;
}
return false;
}
/**
*
*/
@@ -300,4 +210,94 @@ class UpgradeLiabilitiesEight extends Command
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
/**
* @param Account $account
* @return void
*/
private function reverseOpeningBalance(Account $account): void
{
$openingBalanceType = TransactionType::whereType(TransactionType::OPENING_BALANCE)->first();
/** @var TransactionJournal $openingJournal */
$openingJournal = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $account->id)
->where('transaction_journals.transaction_type_id', $openingBalanceType->id)
->first(['transaction_journals.*']);
/** @var Transaction|null $source */
$source = $openingJournal->transactions()->where('amount', '<', 0)->first();
/** @var Transaction|null $dest */
$dest = $openingJournal->transactions()->where('amount', '>', 0)->first();
if ($source && $dest) {
$sourceId = $source->account_id;
$destId = $dest->account_id;
$dest->account_id = $sourceId;
$source->account_id = $destId;
$source->save();
$dest->save();
Log::debug(sprintf('Opening balance transaction journal #%d reversed.', $openingJournal->id));
return;
}
Log::warning('Did not find opening balance.');
}
/**
* @param User $user
*/
private function upgradeForUser(User $user): void
{
Log::debug(sprintf('Upgrading liabilities for user #%d', $user->id));
$accounts = $user->accounts()
->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->whereIn('account_types.type', config('firefly.valid_liabilities'))
->get(['accounts.*']);
/** @var Account $account */
foreach ($accounts as $account) {
$this->upgradeLiability($account);
$service = app(CreditRecalculateService::class);
$service->setAccount($account);
$service->recalculate();
}
}
/**
*
*/
private function upgradeLiabilities(): void
{
Log::debug('Upgrading liabilities.');
$users = User::get();
/** @var User $user */
foreach ($users as $user) {
$this->upgradeForUser($user);
}
}
/**
* @param Account $account
*/
private function upgradeLiability(Account $account): void
{
Log::debug(sprintf('Upgrade liability #%d ("%s")', $account->id, $account->name));
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$repository->setUser($account->user);
$direction = $repository->getMetaValue($account, 'liability_direction');
if ('debit' === $direction) {
Log::debug('Direction is debit ("I owe this amount"), so no need to upgrade.');
}
if ('credit' === $direction && $this->hasBadOpening($account)) {
$this->deleteCreditTransaction($account);
$this->reverseOpeningBalance($account);
$this->line(sprintf('Corrected opening balance for liability #%d ("%s")', $account->id, $account->name));
}
if ('credit' === $direction) {
$count = $this->deleteTransactions($account);
if ($count > 0) {
$this->line(sprintf('Removed %d old format transaction(s) for liability #%d ("%s")', $count, $account->id, $account->name));
}
}
Log::debug(sprintf('Done upgrading liability #%d ("%s")', $account->id, $account->name));
}
}