chore: reformat code.

This commit is contained in:
James Cole
2023-06-21 12:34:58 +02:00
parent 8d87abde64
commit 3dcb35710b
799 changed files with 23319 additions and 22173 deletions

View File

@@ -63,19 +63,11 @@ class AccountUpdateService
$this->accountRepository = app(AccountRepositoryInterface::class);
}
/**
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
}
/**
* Update account data.
*
* @param Account $account
* @param array $data
* @param Account $account
* @param array $data
*
* @return Account
* @throws FireflyException
@@ -122,8 +114,83 @@ class AccountUpdateService
}
/**
* @param Account $account
* @param array $data
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
}
/**
* @param Account $account
* @param array $data
*
* @return Account
*/
private function updateAccount(Account $account, array $data): Account
{
// update the account itself:
if (array_key_exists('name', $data)) {
$account->name = $data['name'];
}
if (array_key_exists('active', $data)) {
$account->active = $data['active'];
}
if (array_key_exists('iban', $data)) {
$account->iban = app('steam')->filterSpaces((string)$data['iban']);
}
// set liability, but account must already be a liability.
//$liabilityType = $data['liability_type'] ?? '';
if ($this->isLiability($account) && array_key_exists('liability_type', $data)) {
$type = $this->getAccountType($data['liability_type']);
$account->account_type_id = $type->id;
}
// set liability, alternative method used in v1 layout:
if ($this->isLiability($account) && array_key_exists('account_type_id', $data)) {
$type = AccountType::find((int)$data['account_type_id']);
if (null !== $type && in_array($type->type, config('firefly.valid_liabilities'), true)) {
$account->account_type_id = $type->id;
}
}
// update virtual balance (could be set to zero if empty string).
if (array_key_exists('virtual_balance', $data) && null !== $data['virtual_balance']) {
$account->virtual_balance = '' === trim($data['virtual_balance']) ? '0' : $data['virtual_balance'];
}
$account->save();
return $account;
}
/**
* @param Account $account
*
* @return bool
*/
private function isLiability(Account $account): bool
{
$type = $account->accountType->type;
return in_array($type, [AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE], true);
}
/**
* @param string $type
*
* @return AccountType
*/
private function getAccountType(string $type): AccountType
{
return AccountType::whereType(ucfirst($type))->first();
}
/**
* @param Account $account
* @param array $data
*
* @return Account
*/
@@ -174,16 +241,6 @@ class AccountUpdateService
return $account;
}
/**
* @param string $type
*
* @return AccountType
*/
private function getAccountType(string $type): AccountType
{
return AccountType::whereType(ucfirst($type))->first();
}
private function getTypeIds(array $array): array
{
$return = [];
@@ -198,65 +255,8 @@ class AccountUpdateService
}
/**
* @param Account $account
*
* @return bool
*/
private function isLiability(Account $account): bool
{
$type = $account->accountType->type;
return in_array($type, [AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE], true);
}
/**
* @param Account $account
* @param array $data
*
* @return Account
*/
private function updateAccount(Account $account, array $data): Account
{
// update the account itself:
if (array_key_exists('name', $data)) {
$account->name = $data['name'];
}
if (array_key_exists('active', $data)) {
$account->active = $data['active'];
}
if (array_key_exists('iban', $data)) {
$account->iban = app('steam')->filterSpaces((string)$data['iban']);
}
// set liability, but account must already be a liability.
//$liabilityType = $data['liability_type'] ?? '';
if ($this->isLiability($account) && array_key_exists('liability_type', $data)) {
$type = $this->getAccountType($data['liability_type']);
$account->account_type_id = $type->id;
}
// set liability, alternative method used in v1 layout:
if ($this->isLiability($account) && array_key_exists('account_type_id', $data)) {
$type = AccountType::find((int)$data['account_type_id']);
if (null !== $type && in_array($type->type, config('firefly.valid_liabilities'), true)) {
$account->account_type_id = $type->id;
}
}
// update virtual balance (could be set to zero if empty string).
if (array_key_exists('virtual_balance', $data) && null !== $data['virtual_balance']) {
$account->virtual_balance = '' === trim($data['virtual_balance']) ? '0' : $data['virtual_balance'];
}
$account->save();
return $account;
}
/**
* @param Account $account
* @param array $data
* @param Account $account
* @param array $data
*/
private function updateLocation(Account $account, array $data): void
{
@@ -285,8 +285,8 @@ class AccountUpdateService
}
/**
* @param Account $account
* @param array $data
* @param Account $account
* @param array $data
*
* @throws FireflyException
*/
@@ -321,7 +321,7 @@ class AccountUpdateService
}
/**
* @param Account $account
* @param Account $account
*
* @throws FireflyException
*/

View File

@@ -47,8 +47,8 @@ class BillUpdateService
protected User $user;
/**
* @param Bill $bill
* @param array $data
* @param Bill $bill
* @param array $data
*
* @return Bill
* @throws FireflyException
@@ -141,19 +141,8 @@ class BillUpdateService
}
/**
* @param Rule $rule
* @param string $key
*
* @return RuleTrigger|null
*/
private function getRuleTrigger(Rule $rule, string $key): ?RuleTrigger
{
return $rule->ruleTriggers()->where('trigger_type', $key)->first();
}
/**
* @param Bill $bill
* @param array $data
* @param Bill $bill
* @param array $data
*
* @return Bill
*/
@@ -196,9 +185,32 @@ class BillUpdateService
}
/**
* @param Bill $bill
* @param array $oldData
* @param array $newData
* @param Bill $bill
* @param int $oldOrder
* @param int $newOrder
*/
private function updateOrder(Bill $bill, int $oldOrder, int $newOrder): void
{
if ($newOrder > $oldOrder) {
$this->user->bills()->where('order', '<=', $newOrder)->where('order', '>', $oldOrder)
->where('bills.id', '!=', $bill->id)
->decrement('bills.order');
$bill->order = $newOrder;
$bill->save();
}
if ($newOrder < $oldOrder) {
$this->user->bills()->where('order', '>=', $newOrder)->where('order', '<', $oldOrder)
->where('bills.id', '!=', $bill->id)
->increment('bills.order');
$bill->order = $newOrder;
$bill->save();
}
}
/**
* @param Bill $bill
* @param array $oldData
* @param array $newData
*/
private function updateBillTriggers(Bill $bill, array $oldData, array $newData): void
{
@@ -232,33 +244,10 @@ class BillUpdateService
}
/**
* @param Bill $bill
* @param int $oldOrder
* @param int $newOrder
*/
private function updateOrder(Bill $bill, int $oldOrder, int $newOrder): void
{
if ($newOrder > $oldOrder) {
$this->user->bills()->where('order', '<=', $newOrder)->where('order', '>', $oldOrder)
->where('bills.id', '!=', $bill->id)
->decrement('bills.order');
$bill->order = $newOrder;
$bill->save();
}
if ($newOrder < $oldOrder) {
$this->user->bills()->where('order', '>=', $newOrder)->where('order', '<', $oldOrder)
->where('bills.id', '!=', $bill->id)
->increment('bills.order');
$bill->order = $newOrder;
$bill->save();
}
}
/**
* @param Collection $rules
* @param string $key
* @param string $oldValue
* @param string $newValue
* @param Collection $rules
* @param string $key
* @param string $oldValue
* @param string $newValue
*/
private function updateRules(Collection $rules, string $key, string $oldValue, string $newValue): void
{
@@ -279,4 +268,15 @@ class BillUpdateService
}
}
}
/**
* @param Rule $rule
* @param string $key
*
* @return RuleTrigger|null
*/
private function getRuleTrigger(Rule $rule, string $key): ?RuleTrigger
{
return $rule->ruleTriggers()->where('trigger_type', $key)->first();
}
}

View File

@@ -51,7 +51,7 @@ class CategoryUpdateService
}
/**
* @param mixed $user
* @param mixed $user
*/
public function setUser($user): void
{
@@ -59,8 +59,8 @@ class CategoryUpdateService
}
/**
* @param Category $category
* @param array $data
* @param Category $category
* @param array $data
*
* @return Category
* @throws Exception
@@ -83,8 +83,64 @@ class CategoryUpdateService
}
/**
* @param Category $category
* @param array $data
* @param string $oldName
* @param string $newName
*/
private function updateRuleTriggers(string $oldName, string $newName): void
{
$types = ['category_is',];
$triggers = RuleTrigger::leftJoin('rules', 'rules.id', '=', 'rule_triggers.rule_id')
->where('rules.user_id', $this->user->id)
->whereIn('rule_triggers.trigger_type', $types)
->where('rule_triggers.trigger_value', $oldName)
->get(['rule_triggers.*']);
Log::debug(sprintf('Found %d triggers to update.', $triggers->count()));
/** @var RuleTrigger $trigger */
foreach ($triggers as $trigger) {
$trigger->trigger_value = $newName;
$trigger->save();
Log::debug(sprintf('Updated trigger %d: %s', $trigger->id, $trigger->trigger_value));
}
}
/**
* @param string $oldName
* @param string $newName
*/
private function updateRuleActions(string $oldName, string $newName): void
{
$types = ['set_category',];
$actions = RuleAction::leftJoin('rules', 'rules.id', '=', 'rule_actions.rule_id')
->where('rules.user_id', $this->user->id)
->whereIn('rule_actions.action_type', $types)
->where('rule_actions.action_value', $oldName)
->get(['rule_actions.*']);
Log::debug(sprintf('Found %d actions to update.', $actions->count()));
/** @var RuleAction $action */
foreach ($actions as $action) {
$action->action_value = $newName;
$action->save();
Log::debug(sprintf('Updated action %d: %s', $action->id, $action->action_value));
}
}
/**
* @param string $oldName
* @param string $newName
*/
private function updateRecurrences(string $oldName, string $newName): void
{
RecurrenceTransactionMeta::leftJoin('recurrences_transactions', 'rt_meta.rt_id', '=', 'recurrences_transactions.id')
->leftJoin('recurrences', 'recurrences.id', '=', 'recurrences_transactions.recurrence_id')
->where('recurrences.user_id', $this->user->id)
->where('rt_meta.name', 'category_name')
->where('rt_meta.value', $oldName)
->update(['rt_meta.value' => $newName]);
}
/**
* @param Category $category
* @param array $data
*
* @throws Exception
*/
@@ -110,60 +166,4 @@ class CategoryUpdateService
$dbNote->text = trim($note);
$dbNote->save();
}
/**
* @param string $oldName
* @param string $newName
*/
private function updateRecurrences(string $oldName, string $newName): void
{
RecurrenceTransactionMeta::leftJoin('recurrences_transactions', 'rt_meta.rt_id', '=', 'recurrences_transactions.id')
->leftJoin('recurrences', 'recurrences.id', '=', 'recurrences_transactions.recurrence_id')
->where('recurrences.user_id', $this->user->id)
->where('rt_meta.name', 'category_name')
->where('rt_meta.value', $oldName)
->update(['rt_meta.value' => $newName]);
}
/**
* @param string $oldName
* @param string $newName
*/
private function updateRuleActions(string $oldName, string $newName): void
{
$types = ['set_category',];
$actions = RuleAction::leftJoin('rules', 'rules.id', '=', 'rule_actions.rule_id')
->where('rules.user_id', $this->user->id)
->whereIn('rule_actions.action_type', $types)
->where('rule_actions.action_value', $oldName)
->get(['rule_actions.*']);
Log::debug(sprintf('Found %d actions to update.', $actions->count()));
/** @var RuleAction $action */
foreach ($actions as $action) {
$action->action_value = $newName;
$action->save();
Log::debug(sprintf('Updated action %d: %s', $action->id, $action->action_value));
}
}
/**
* @param string $oldName
* @param string $newName
*/
private function updateRuleTriggers(string $oldName, string $newName): void
{
$types = ['category_is',];
$triggers = RuleTrigger::leftJoin('rules', 'rules.id', '=', 'rule_triggers.rule_id')
->where('rules.user_id', $this->user->id)
->whereIn('rule_triggers.trigger_type', $types)
->where('rule_triggers.trigger_value', $oldName)
->get(['rule_triggers.*']);
Log::debug(sprintf('Found %d triggers to update.', $triggers->count()));
/** @var RuleTrigger $trigger */
foreach ($triggers as $trigger) {
$trigger->trigger_value = $newName;
$trigger->save();
Log::debug(sprintf('Updated trigger %d: %s', $trigger->id, $trigger->trigger_value));
}
}
}

View File

@@ -33,8 +33,8 @@ use FireflyIII\Models\TransactionCurrency;
class CurrencyUpdateService
{
/**
* @param TransactionCurrency $currency
* @param array $data
* @param TransactionCurrency $currency
* @param array $data
*
* @return TransactionCurrency
*/

View File

@@ -40,7 +40,7 @@ use FireflyIII\Models\TransactionJournalMeta;
class GroupCloneService
{
/**
* @param TransactionGroup $group
* @param TransactionGroup $group
*
* @return TransactionGroup
*/
@@ -56,9 +56,9 @@ class GroupCloneService
}
/**
* @param TransactionJournal $journal
* @param TransactionGroup $newGroup
* @param int $originalGroup
* @param TransactionJournal $journal
* @param TransactionGroup $newGroup
* @param int $originalGroup
*/
private function cloneJournal(TransactionJournal $journal, TransactionGroup $newGroup, int $originalGroup): void
{
@@ -115,22 +115,21 @@ class GroupCloneService
}
/**
* @param TransactionJournalMeta $meta
* @param TransactionJournal $newJournal
* @param Transaction $transaction
* @param TransactionJournal $newJournal
*/
private function cloneMeta(TransactionJournalMeta $meta, TransactionJournal $newJournal): void
private function cloneTransaction(Transaction $transaction, TransactionJournal $newJournal): void
{
$newMeta = $meta->replicate();
$newMeta->transaction_journal_id = $newJournal->id;
if ('recurrence_id' !== $newMeta->name) {
$newMeta->save();
}
$newTransaction = $transaction->replicate();
$newTransaction->transaction_journal_id = $newJournal->id;
$newTransaction->reconciled = false;
$newTransaction->save();
}
/**
* @param Note $note
* @param TransactionJournal $newJournal
* @param int $oldGroupId
* @param Note $note
* @param TransactionJournal $newJournal
* @param int $oldGroupId
*/
private function cloneNote(Note $note, TransactionJournal $newJournal, int $oldGroupId): void
{
@@ -144,14 +143,15 @@ class GroupCloneService
}
/**
* @param Transaction $transaction
* @param TransactionJournal $newJournal
* @param TransactionJournalMeta $meta
* @param TransactionJournal $newJournal
*/
private function cloneTransaction(Transaction $transaction, TransactionJournal $newJournal): void
private function cloneMeta(TransactionJournalMeta $meta, TransactionJournal $newJournal): void
{
$newTransaction = $transaction->replicate();
$newTransaction->transaction_journal_id = $newJournal->id;
$newTransaction->reconciled = false;
$newTransaction->save();
$newMeta = $meta->replicate();
$newMeta->transaction_journal_id = $newJournal->id;
if ('recurrence_id' !== $newMeta->name) {
$newMeta->save();
}
}
}

View File

@@ -124,49 +124,6 @@ class GroupUpdateService
return $transactionGroup;
}
/**
* @param TransactionGroup $transactionGroup
* @param array $data
*
* @return TransactionJournal|null
*
* @throws DuplicateTransactionException
* @throws FireflyException
* @throws JsonException
*/
private function createTransactionJournal(TransactionGroup $transactionGroup, array $data): ?TransactionJournal
{
$submission = [
'transactions' => [
$data,
],
];
/** @var TransactionJournalFactory $factory */
$factory = app(TransactionJournalFactory::class);
$factory->setUser($transactionGroup->user);
try {
$collection = $factory->create($submission);
} catch (FireflyException $e) {
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
throw new FireflyException(
sprintf('Could not create new transaction journal: %s', $e->getMessage()),
0,
$e
);
}
$collection->each(
function (TransactionJournal $journal) use ($transactionGroup) {
$transactionGroup->transactionJournals()->save($journal);
}
);
if (0 === $collection->count()) {
return null;
}
return $collection->first();
}
/**
* Update single journal.
*
@@ -252,4 +209,47 @@ class GroupUpdateService
return $updated;
}
/**
* @param TransactionGroup $transactionGroup
* @param array $data
*
* @return TransactionJournal|null
*
* @throws DuplicateTransactionException
* @throws FireflyException
* @throws JsonException
*/
private function createTransactionJournal(TransactionGroup $transactionGroup, array $data): ?TransactionJournal
{
$submission = [
'transactions' => [
$data,
],
];
/** @var TransactionJournalFactory $factory */
$factory = app(TransactionJournalFactory::class);
$factory->setUser($transactionGroup->user);
try {
$collection = $factory->create($submission);
} catch (FireflyException $e) {
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
throw new FireflyException(
sprintf('Could not create new transaction journal: %s', $e->getMessage()),
0,
$e
);
}
$collection->each(
function (TransactionJournal $journal) use ($transactionGroup) {
$transactionGroup->transactionJournals()->save($journal);
}
);
if (0 === $collection->count()) {
return null;
}
return $collection->first();
}
}

View File

@@ -183,49 +183,78 @@ class JournalUpdateService
}
/**
* Get destination transaction.
*
* @return Transaction
* @return bool
*/
private function getDestinationTransaction(): Transaction
private function removeReconciliation(): bool
{
if (null === $this->destinationTransaction) {
$this->destinationTransaction = $this->transactionJournal->transactions()->where('amount', '>', 0)->first();
if (count($this->data) > 1) {
return true;
}
if (1 === count($this->data) && true === array_key_exists('transaction_journal_id', $this->data)) {
return true;
}
return $this->destinationTransaction;
return false;
}
/**
* This method returns the current or expected type of the journal (in case of a change) based on the data in the
* array.
*
* If the array contains key 'type' and the value is correct, this is returned. Otherwise, the original type is
* returned.
*
* @return string
* @return bool
*/
private function getExpectedType(): string
private function hasValidAccounts(): bool
{
Log::debug('Now in getExpectedType()');
if ($this->hasFields(['type'])) {
return ucfirst('opening-balance' === $this->data['type'] ? 'opening balance' : $this->data['type']);
}
return $this->transactionJournal->transactionType->type;
return $this->hasValidSourceAccount() && $this->hasValidDestinationAccount();
}
/**
* @return Account
* @return bool
*/
private function getOriginalDestinationAccount(): Account
private function hasValidSourceAccount(): bool
{
if (null === $this->destinationAccount) {
$destination = $this->getDestinationTransaction();
$this->destinationAccount = $destination->account;
Log::debug('Now in hasValidSourceAccount().');
$sourceId = $this->data['source_id'] ?? null;
$sourceName = $this->data['source_name'] ?? null;
if (!$this->hasFields(['source_id', 'source_name'])) {
$origSourceAccount = $this->getOriginalSourceAccount();
$sourceId = $origSourceAccount->id;
$sourceName = $origSourceAccount->name;
}
return $this->destinationAccount;
// make new account validator.
$expectedType = $this->getExpectedType();
Log::debug(sprintf('Expected type (new or unchanged) is %s', $expectedType));
// make a new validator.
/** @var AccountValidator $validator */
$validator = app(AccountValidator::class);
$validator->setTransactionType($expectedType);
$validator->setUser($this->transactionJournal->user);
$result = $validator->validateSource(['id' => $sourceId]);
Log::debug(
sprintf('hasValidSourceAccount(%d, "%s") will return %s', $sourceId, $sourceName, var_export($result, true))
);
// TODO typeoverrule the account validator may have a different opinion on the transaction type.
// validate submitted info:
return $result;
}
/**
* @param array $fields
*
* @return bool
*/
private function hasFields(array $fields): bool
{
foreach ($fields as $field) {
if (array_key_exists($field, $this->data)) {
return true;
}
}
return false;
}
/**
@@ -259,96 +288,22 @@ class JournalUpdateService
}
/**
* Does a validation and returns the destination account. This method will break if the dest isn't really valid.
* This method returns the current or expected type of the journal (in case of a change) based on the data in the
* array.
*
* @return Account
*/
private function getValidDestinationAccount(): Account
{
Log::debug('Now in getValidDestinationAccount().');
if (!$this->hasFields(['destination_id', 'destination_name'])) {
return $this->getOriginalDestinationAccount();
}
$destInfo = [
'id' => (int)($this->data['destination_id'] ?? null),
'name' => $this->data['destination_name'] ?? null,
'iban' => $this->data['destination_iban'] ?? null,
'number' => $this->data['destination_number'] ?? null,
'bic' => $this->data['destination_bic'] ?? null,
];
// make new account validator.
$expectedType = $this->getExpectedType();
Log::debug(sprintf('Expected type (new or unchanged) is %s', $expectedType));
try {
$result = $this->getAccount($expectedType, 'destination', $destInfo);
} catch (FireflyException $e) {
Log::error(sprintf('getValidDestinationAccount() threw unexpected error: %s', $e->getMessage()));
$result = $this->getOriginalDestinationAccount();
}
return $result;
}
/**
* Does a validation and returns the source account. This method will break if the source isn't really valid.
* If the array contains key 'type' and the value is correct, this is returned. Otherwise, the original type is
* returned.
*
* @return Account
* @return string
*/
private function getValidSourceAccount(): Account
private function getExpectedType(): string
{
Log::debug('Now in getValidSourceAccount().');
if (!$this->hasFields(['source_id', 'source_name'])) {
return $this->getOriginalSourceAccount();
Log::debug('Now in getExpectedType()');
if ($this->hasFields(['type'])) {
return ucfirst('opening-balance' === $this->data['type'] ? 'opening balance' : $this->data['type']);
}
$sourceInfo = [
'id' => (int)($this->data['source_id'] ?? null),
'name' => $this->data['source_name'] ?? null,
'iban' => $this->data['source_iban'] ?? null,
'number' => $this->data['source_number'] ?? null,
'bic' => $this->data['source_bic'] ?? null,
];
$expectedType = $this->getExpectedType();
try {
$result = $this->getAccount($expectedType, 'source', $sourceInfo);
} catch (FireflyException $e) {
Log::error(sprintf('Cant get the valid source account: %s', $e->getMessage()));
$result = $this->getOriginalSourceAccount();
}
Log::debug(sprintf('getValidSourceAccount() will return #%d ("%s")', $result->id, $result->name));
return $result;
}
/**
* @param array $fields
*
* @return bool
*/
private function hasFields(array $fields): bool
{
foreach ($fields as $field) {
if (array_key_exists($field, $this->data)) {
return true;
}
}
return false;
}
/**
* @return bool
*/
private function hasValidAccounts(): bool
{
return $this->hasValidSourceAccount() && $this->hasValidDestinationAccount();
return $this->transactionJournal->transactionType->type;
}
/**
@@ -394,54 +349,65 @@ class JournalUpdateService
}
/**
* @return bool
* @return Account
*/
private function hasValidSourceAccount(): bool
private function getOriginalDestinationAccount(): Account
{
Log::debug('Now in hasValidSourceAccount().');
$sourceId = $this->data['source_id'] ?? null;
$sourceName = $this->data['source_name'] ?? null;
if (!$this->hasFields(['source_id', 'source_name'])) {
$origSourceAccount = $this->getOriginalSourceAccount();
$sourceId = $origSourceAccount->id;
$sourceName = $origSourceAccount->name;
if (null === $this->destinationAccount) {
$destination = $this->getDestinationTransaction();
$this->destinationAccount = $destination->account;
}
// make new account validator.
$expectedType = $this->getExpectedType();
Log::debug(sprintf('Expected type (new or unchanged) is %s', $expectedType));
// make a new validator.
/** @var AccountValidator $validator */
$validator = app(AccountValidator::class);
$validator->setTransactionType($expectedType);
$validator->setUser($this->transactionJournal->user);
$result = $validator->validateSource(['id' => $sourceId]);
Log::debug(
sprintf('hasValidSourceAccount(%d, "%s") will return %s', $sourceId, $sourceName, var_export($result, true))
);
// TODO typeoverrule the account validator may have a different opinion on the transaction type.
// validate submitted info:
return $result;
return $this->destinationAccount;
}
/**
* @return bool
* Get destination transaction.
*
* @return Transaction
*/
private function removeReconciliation(): bool
private function getDestinationTransaction(): Transaction
{
if (count($this->data) > 1) {
return true;
}
if (1 === count($this->data) && true === array_key_exists('transaction_journal_id', $this->data)) {
return true;
if (null === $this->destinationTransaction) {
$this->destinationTransaction = $this->transactionJournal->transactions()->where('amount', '>', 0)->first();
}
return false;
return $this->destinationTransaction;
}
/**
* Does a validation and returns the source account. This method will break if the source isn't really valid.
*
* @return Account
*/
private function getValidSourceAccount(): Account
{
Log::debug('Now in getValidSourceAccount().');
if (!$this->hasFields(['source_id', 'source_name'])) {
return $this->getOriginalSourceAccount();
}
$sourceInfo = [
'id' => (int)($this->data['source_id'] ?? null),
'name' => $this->data['source_name'] ?? null,
'iban' => $this->data['source_iban'] ?? null,
'number' => $this->data['source_number'] ?? null,
'bic' => $this->data['source_bic'] ?? null,
];
$expectedType = $this->getExpectedType();
try {
$result = $this->getAccount($expectedType, 'source', $sourceInfo);
} catch (FireflyException $e) {
Log::error(sprintf('Cant get the valid source account: %s', $e->getMessage()));
$result = $this->getOriginalSourceAccount();
}
Log::debug(sprintf('getValidSourceAccount() will return #%d ("%s")', $result->id, $result->name));
return $result;
}
/**
@@ -475,34 +441,70 @@ class JournalUpdateService
}
/**
* Does a validation and returns the destination account. This method will break if the dest isn't really valid.
*
* @return Account
*/
private function updateAmount(): void
private function getValidDestinationAccount(): Account
{
Log::debug(sprintf('Now in %s', __METHOD__));
if (!$this->hasFields(['amount'])) {
return;
Log::debug('Now in getValidDestinationAccount().');
if (!$this->hasFields(['destination_id', 'destination_name'])) {
return $this->getOriginalDestinationAccount();
}
$value = $this->data['amount'] ?? '';
Log::debug(sprintf('Amount is now "%s"', $value));
$destInfo = [
'id' => (int)($this->data['destination_id'] ?? null),
'name' => $this->data['destination_name'] ?? null,
'iban' => $this->data['destination_iban'] ?? null,
'number' => $this->data['destination_number'] ?? null,
'bic' => $this->data['destination_bic'] ?? null,
];
// make new account validator.
$expectedType = $this->getExpectedType();
Log::debug(sprintf('Expected type (new or unchanged) is %s', $expectedType));
try {
$amount = $this->getAmount($value);
$result = $this->getAccount($expectedType, 'destination', $destInfo);
} catch (FireflyException $e) {
Log::debug(sprintf('getAmount("%s") returns error: %s', $value, $e->getMessage()));
Log::error(sprintf('getValidDestinationAccount() threw unexpected error: %s', $e->getMessage()));
$result = $this->getOriginalDestinationAccount();
}
return $result;
}
/**
* Updates journal transaction type.
*/
private function updateType(): void
{
Log::debug('Now in updateType()');
if ($this->hasFields(['type'])) {
$type = 'opening-balance' === $this->data['type'] ? 'opening balance' : $this->data['type'];
Log::debug(
sprintf(
'Trying to change journal #%d from a %s to a %s.',
$this->transactionJournal->id,
$this->transactionJournal->transactionType->type,
$type
)
);
/** @var TransactionTypeFactory $typeFactory */
$typeFactory = app(TransactionTypeFactory::class);
$result = $typeFactory->find($this->data['type']);
if (null !== $result) {
Log::debug('Changed transaction type!');
$this->transactionJournal->transaction_type_id = $result->id;
$this->transactionJournal->save();
return;
}
return;
}
$origSourceTransaction = $this->getSourceTransaction();
$origSourceTransaction->amount = app('steam')->negative($amount);
$origSourceTransaction->save();
$destTransaction = $this->getDestinationTransaction();
$destTransaction->amount = app('steam')->positive($amount);
$destTransaction->save();
// refresh transactions.
$this->sourceTransaction->refresh();
$this->destinationTransaction->refresh();
Log::debug(sprintf('Updated amount to "%s"', $amount));
Log::debug('No type field present.');
}
/**
@@ -525,67 +527,6 @@ class JournalUpdateService
}
}
/**
*
*/
private function updateBudget(): void
{
// update budget
if ($this->hasFields(['budget_id', 'budget_name'])) {
Log::debug('Will update budget.');
$this->storeBudget($this->transactionJournal, new NullArrayObject($this->data));
}
// is transfer? remove budget
if (TransactionType::TRANSFER === $this->transactionJournal->transactionType->type) {
$this->transactionJournal->budgets()->sync([]);
}
}
/**
*
*/
private function updateCategory(): void
{
// update category
if ($this->hasFields(['category_id', 'category_name'])) {
Log::debug('Will update category.');
$this->storeCategory($this->transactionJournal, new NullArrayObject($this->data));
}
}
/**
*
*/
private function updateCurrency(): void
{
// update transactions.
if (!$this->hasFields(['currency_id', 'currency_code'])) {
return;
}
$currencyId = $this->data['currency_id'] ?? null;
$currencyCode = $this->data['currency_code'] ?? null;
$currency = $this->currencyRepository->findCurrency($currencyId, $currencyCode);
if (null !== $currency) {
// update currency everywhere.
$this->transactionJournal->transaction_currency_id = $currency->id;
$this->transactionJournal->save();
$source = $this->getSourceTransaction();
$source->transaction_currency_id = $currency->id;
$source->save();
$dest = $this->getDestinationTransaction();
$dest->transaction_currency_id = $currency->id;
$dest->save();
// refresh transactions.
$this->sourceTransaction->refresh();
$this->destinationTransaction->refresh();
Log::debug(sprintf('Updated currency to #%d (%s)', $currency->id, $currency->code));
}
}
/**
* Update journal generic field. Cannot be set to NULL.
*
@@ -622,6 +563,201 @@ class JournalUpdateService
}
}
/**
*
*/
private function updateCategory(): void
{
// update category
if ($this->hasFields(['category_id', 'category_name'])) {
Log::debug('Will update category.');
$this->storeCategory($this->transactionJournal, new NullArrayObject($this->data));
}
}
/**
*
*/
private function updateBudget(): void
{
// update budget
if ($this->hasFields(['budget_id', 'budget_name'])) {
Log::debug('Will update budget.');
$this->storeBudget($this->transactionJournal, new NullArrayObject($this->data));
}
// is transfer? remove budget
if (TransactionType::TRANSFER === $this->transactionJournal->transactionType->type) {
$this->transactionJournal->budgets()->sync([]);
}
}
/**
*
*/
private function updateTags(): void
{
if ($this->hasFields(['tags'])) {
Log::debug('Will update tags.');
$tags = $this->data['tags'] ?? null;
$this->storeTags($this->transactionJournal, $tags);
}
}
/**
*
*/
private function updateReconciled(): void
{
if (array_key_exists('reconciled', $this->data) && is_bool($this->data['reconciled'])) {
$this->transactionJournal->transactions()->update(['reconciled' => $this->data['reconciled']]);
}
}
/**
*
*/
private function updateNotes(): void
{
// update notes.
if ($this->hasFields(['notes'])) {
$notes = '' === (string)$this->data['notes'] ? null : $this->data['notes'];
$this->storeNotes($this->transactionJournal, $notes);
}
}
/**
*
*/
private function updateMeta(): void
{
// update meta fields.
// first string
if ($this->hasFields($this->metaString)) {
Log::debug('Meta string fields are present.');
$this->updateMetaFields();
}
// then date fields.
if ($this->hasFields($this->metaDate)) {
Log::debug('Meta date fields are present.');
$this->updateMetaDateFields();
}
}
/**
*
*/
private function updateMetaFields(): void
{
/** @var TransactionJournalMetaFactory $factory */
$factory = app(TransactionJournalMetaFactory::class);
foreach ($this->metaString as $field) {
if ($this->hasFields([$field])) {
$value = '' === $this->data[$field] ? null : $this->data[$field];
Log::debug(sprintf('Field "%s" is present ("%s"), try to update it.', $field, $value));
$set = [
'journal' => $this->transactionJournal,
'name' => $field,
'data' => $value,
];
$factory->updateOrCreate($set);
}
}
}
/**
*
*/
private function updateMetaDateFields(): void
{
/** @var TransactionJournalMetaFactory $factory */
$factory = app(TransactionJournalMetaFactory::class);
foreach ($this->metaDate as $field) {
if ($this->hasFields([$field])) {
try {
$value = '' === (string)$this->data[$field] ? null : new Carbon($this->data[$field]);
} catch (InvalidDateException $e) {
Log::debug(sprintf('%s is not a valid date value: %s', $this->data[$field], $e->getMessage()));
return;
}
Log::debug(sprintf('Field "%s" is present ("%s"), try to update it.', $field, $value));
$set = [
'journal' => $this->transactionJournal,
'name' => $field,
'data' => $value,
];
$factory->updateOrCreate($set);
}
}
}
/**
*
*/
private function updateCurrency(): void
{
// update transactions.
if (!$this->hasFields(['currency_id', 'currency_code'])) {
return;
}
$currencyId = $this->data['currency_id'] ?? null;
$currencyCode = $this->data['currency_code'] ?? null;
$currency = $this->currencyRepository->findCurrency($currencyId, $currencyCode);
if (null !== $currency) {
// update currency everywhere.
$this->transactionJournal->transaction_currency_id = $currency->id;
$this->transactionJournal->save();
$source = $this->getSourceTransaction();
$source->transaction_currency_id = $currency->id;
$source->save();
$dest = $this->getDestinationTransaction();
$dest->transaction_currency_id = $currency->id;
$dest->save();
// refresh transactions.
$this->sourceTransaction->refresh();
$this->destinationTransaction->refresh();
Log::debug(sprintf('Updated currency to #%d (%s)', $currency->id, $currency->code));
}
}
/**
*
*/
private function updateAmount(): void
{
Log::debug(sprintf('Now in %s', __METHOD__));
if (!$this->hasFields(['amount'])) {
return;
}
$value = $this->data['amount'] ?? '';
Log::debug(sprintf('Amount is now "%s"', $value));
try {
$amount = $this->getAmount($value);
} catch (FireflyException $e) {
Log::debug(sprintf('getAmount("%s") returns error: %s', $value, $e->getMessage()));
return;
}
$origSourceTransaction = $this->getSourceTransaction();
$origSourceTransaction->amount = app('steam')->negative($amount);
$origSourceTransaction->save();
$destTransaction = $this->getDestinationTransaction();
$destTransaction->amount = app('steam')->positive($amount);
$destTransaction->save();
// refresh transactions.
$this->sourceTransaction->refresh();
$this->destinationTransaction->refresh();
Log::debug(sprintf('Updated amount to "%s"', $amount));
}
/**
*
*/
@@ -691,140 +827,4 @@ class JournalUpdateService
$this->sourceTransaction->refresh();
$this->destinationTransaction->refresh();
}
/**
*
*/
private function updateMeta(): void
{
// update meta fields.
// first string
if ($this->hasFields($this->metaString)) {
Log::debug('Meta string fields are present.');
$this->updateMetaFields();
}
// then date fields.
if ($this->hasFields($this->metaDate)) {
Log::debug('Meta date fields are present.');
$this->updateMetaDateFields();
}
}
/**
*
*/
private function updateMetaDateFields(): void
{
/** @var TransactionJournalMetaFactory $factory */
$factory = app(TransactionJournalMetaFactory::class);
foreach ($this->metaDate as $field) {
if ($this->hasFields([$field])) {
try {
$value = '' === (string)$this->data[$field] ? null : new Carbon($this->data[$field]);
} catch (InvalidDateException $e) {
Log::debug(sprintf('%s is not a valid date value: %s', $this->data[$field], $e->getMessage()));
return;
}
Log::debug(sprintf('Field "%s" is present ("%s"), try to update it.', $field, $value));
$set = [
'journal' => $this->transactionJournal,
'name' => $field,
'data' => $value,
];
$factory->updateOrCreate($set);
}
}
}
/**
*
*/
private function updateMetaFields(): void
{
/** @var TransactionJournalMetaFactory $factory */
$factory = app(TransactionJournalMetaFactory::class);
foreach ($this->metaString as $field) {
if ($this->hasFields([$field])) {
$value = '' === $this->data[$field] ? null : $this->data[$field];
Log::debug(sprintf('Field "%s" is present ("%s"), try to update it.', $field, $value));
$set = [
'journal' => $this->transactionJournal,
'name' => $field,
'data' => $value,
];
$factory->updateOrCreate($set);
}
}
}
/**
*
*/
private function updateNotes(): void
{
// update notes.
if ($this->hasFields(['notes'])) {
$notes = '' === (string)$this->data['notes'] ? null : $this->data['notes'];
$this->storeNotes($this->transactionJournal, $notes);
}
}
/**
*
*/
private function updateReconciled(): void
{
if (array_key_exists('reconciled', $this->data) && is_bool($this->data['reconciled'])) {
$this->transactionJournal->transactions()->update(['reconciled' => $this->data['reconciled']]);
}
}
/**
*
*/
private function updateTags(): void
{
if ($this->hasFields(['tags'])) {
Log::debug('Will update tags.');
$tags = $this->data['tags'] ?? null;
$this->storeTags($this->transactionJournal, $tags);
}
}
/**
* Updates journal transaction type.
*/
private function updateType(): void
{
Log::debug('Now in updateType()');
if ($this->hasFields(['type'])) {
$type = 'opening-balance' === $this->data['type'] ? 'opening balance' : $this->data['type'];
Log::debug(
sprintf(
'Trying to change journal #%d from a %s to a %s.',
$this->transactionJournal->id,
$this->transactionJournal->transactionType->type,
$type
)
);
/** @var TransactionTypeFactory $typeFactory */
$typeFactory = app(TransactionTypeFactory::class);
$result = $typeFactory->find($this->data['type']);
if (null !== $result) {
Log::debug('Changed transaction type!');
$this->transactionJournal->transaction_type_id = $result->id;
$this->transactionJournal->save();
return;
}
return;
}
Log::debug('No type field present.');
}
}

View File

@@ -33,7 +33,6 @@ use FireflyIII\Services\Internal\Support\RecurringTransactionTrait;
use FireflyIII\Services\Internal\Support\TransactionTypeTrait;
use FireflyIII\User;
use Illuminate\Support\Facades\Log;
use JsonException;
/**
* Class RecurrenceUpdateService
@@ -52,8 +51,8 @@ class RecurrenceUpdateService
*
* TODO if the user updates the type, the accounts must be validated again.
*
* @param Recurrence $recurrence
* @param array $data
* @param Recurrence $recurrence
* @param array $data
*
* @return Recurrence
* @throws FireflyException
@@ -113,19 +112,72 @@ class RecurrenceUpdateService
}
/**
* @param Recurrence $recurrence
* @param int $transactionId
* @return void
* @param Recurrence $recurrence
* @param string $text
*/
private function deleteTransaction(Recurrence $recurrence, int $transactionId): void
private function setNoteText(Recurrence $recurrence, string $text): void
{
Log::debug(sprintf('Will delete transaction #%d in recurrence #%d.', $transactionId, $recurrence->id));
$recurrence->recurrenceTransactions()->where('id', $transactionId)->delete();
$dbNote = $recurrence->notes()->first();
if ('' !== $text) {
if (null === $dbNote) {
$dbNote = new Note();
$dbNote->noteable()->associate($recurrence);
}
$dbNote->text = trim($text);
$dbNote->save();
return;
}
$dbNote?->delete();
}
/**
* @param Recurrence $recurrence
* @param array $data
*
* @param Recurrence $recurrence
* @param array $repetitions
*
* @throws FireflyException
*/
private function updateRepetitions(Recurrence $recurrence, array $repetitions): void
{
$originalCount = $recurrence->recurrenceRepetitions()->count();
if (0 === count($repetitions)) {
// won't drop repetition, rather avoid.
return;
}
// user added or removed repetitions, delete all and recreate:
if ($originalCount !== count($repetitions)) {
Log::debug('Delete existing repetitions and create new ones.');
$this->deleteRepetitions($recurrence);
$this->createRepetitions($recurrence, $repetitions);
return;
}
// loop all and try to match them:
Log::debug('Loop and find');
foreach ($repetitions as $current) {
$match = $this->matchRepetition($recurrence, $current);
if (null === $match) {
throw new FireflyException('Cannot match recurring repetition to existing repetition. Not sure what to do. Break.');
}
$fields = [
'type' => 'repetition_type',
'moment' => 'repetition_moment',
'skip' => 'repetition_skip',
'weekend' => 'weekend',
];
foreach ($fields as $field => $column) {
if (array_key_exists($field, $current)) {
$match->$column = $current[$field];
$match->save();
}
}
}
}
/**
* @param Recurrence $recurrence
* @param array $data
*
* @return RecurrenceRepetition|null
*/
@@ -156,28 +208,69 @@ class RecurrenceUpdateService
}
/**
* @param Recurrence $recurrence
* @param string $text
* TODO this method is very complex.
*
* @param Recurrence $recurrence
* @param array $transactions
*/
private function setNoteText(Recurrence $recurrence, string $text): void
private function updateTransactions(Recurrence $recurrence, array $transactions): void
{
$dbNote = $recurrence->notes()->first();
if ('' !== $text) {
if (null === $dbNote) {
$dbNote = new Note();
$dbNote->noteable()->associate($recurrence);
}
$dbNote->text = trim($text);
$dbNote->save();
Log::debug('Now in updateTransactions()');
$originalCount = $recurrence->recurrenceTransactions()->count();
Log::debug(sprintf('Original count is %d', $originalCount));
if (0 === count($transactions)) {
// won't drop transactions, rather avoid.
Log::warning('No transactions to update, too scared to continue!');
return;
}
$dbNote?->delete();
$combinations = [];
$originalTransactions = $recurrence->recurrenceTransactions()->get()->toArray();
/**
* First, make sure to loop all existing transactions and match them to a counterpart in the submitted transactions array.
*/
foreach ($originalTransactions as $i => $originalTransaction) {
foreach ($transactions as $ii => $submittedTransaction) {
if (array_key_exists('id', $submittedTransaction) && (int)$originalTransaction['id'] === (int)$submittedTransaction['id']) {
Log::debug(sprintf('Match original transaction #%d with an entry in the submitted array.', $originalTransaction['id']));
$combinations[] = [
'original' => $originalTransaction,
'submitted' => $submittedTransaction,
];
unset($originalTransactions[$i]);
unset($transactions[$ii]);
}
}
}
/**
* If one left of both we can match those as well and presto.
*/
if (1 === count($originalTransactions) && 1 === count($transactions)) {
$first = array_shift($originalTransactions);
Log::debug(sprintf('One left of each, link them (ID is #%d)', $first['id']));
$combinations[] = [
'original' => $first,
'submitted' => array_shift($transactions),
];
unset($first);
}
// if they are both empty, we can safely loop all combinations and update them.
if (0 === count($originalTransactions) && 0 === count($transactions)) {
foreach ($combinations as $combination) {
$this->updateCombination($recurrence, $combination);
}
}
// anything left in the original transactions array can be deleted.
foreach ($originalTransactions as $original) {
Log::debug(sprintf('Original transaction #%d is unmatched, delete it!', $original['id']));
$this->deleteTransaction($recurrence, (int)$original['id']);
}
// anything left is new.
$this->createTransactions($recurrence, $transactions);
}
/**
* @param Recurrence $recurrence
* @param array $combination
* @param Recurrence $recurrence
* @param array $combination
* @return void
*/
private function updateCombination(Recurrence $recurrence, array $combination): void
@@ -257,107 +350,13 @@ class RecurrenceUpdateService
}
/**
*
* @param Recurrence $recurrence
* @param array $repetitions
*
* @throws FireflyException
* @param Recurrence $recurrence
* @param int $transactionId
* @return void
*/
private function updateRepetitions(Recurrence $recurrence, array $repetitions): void
private function deleteTransaction(Recurrence $recurrence, int $transactionId): void
{
$originalCount = $recurrence->recurrenceRepetitions()->count();
if (0 === count($repetitions)) {
// won't drop repetition, rather avoid.
return;
}
// user added or removed repetitions, delete all and recreate:
if ($originalCount !== count($repetitions)) {
Log::debug('Delete existing repetitions and create new ones.');
$this->deleteRepetitions($recurrence);
$this->createRepetitions($recurrence, $repetitions);
return;
}
// loop all and try to match them:
Log::debug('Loop and find');
foreach ($repetitions as $current) {
$match = $this->matchRepetition($recurrence, $current);
if (null === $match) {
throw new FireflyException('Cannot match recurring repetition to existing repetition. Not sure what to do. Break.');
}
$fields = [
'type' => 'repetition_type',
'moment' => 'repetition_moment',
'skip' => 'repetition_skip',
'weekend' => 'weekend',
];
foreach ($fields as $field => $column) {
if (array_key_exists($field, $current)) {
$match->$column = $current[$field];
$match->save();
}
}
}
}
/**
* TODO this method is very complex.
*
* @param Recurrence $recurrence
* @param array $transactions
*/
private function updateTransactions(Recurrence $recurrence, array $transactions): void
{
Log::debug('Now in updateTransactions()');
$originalCount = $recurrence->recurrenceTransactions()->count();
Log::debug(sprintf('Original count is %d', $originalCount));
if (0 === count($transactions)) {
// won't drop transactions, rather avoid.
Log::warning('No transactions to update, too scared to continue!');
return;
}
$combinations = [];
$originalTransactions = $recurrence->recurrenceTransactions()->get()->toArray();
/**
* First, make sure to loop all existing transactions and match them to a counterpart in the submitted transactions array.
*/
foreach ($originalTransactions as $i => $originalTransaction) {
foreach ($transactions as $ii => $submittedTransaction) {
if (array_key_exists('id', $submittedTransaction) && (int)$originalTransaction['id'] === (int)$submittedTransaction['id']) {
Log::debug(sprintf('Match original transaction #%d with an entry in the submitted array.', $originalTransaction['id']));
$combinations[] = [
'original' => $originalTransaction,
'submitted' => $submittedTransaction,
];
unset($originalTransactions[$i]);
unset($transactions[$ii]);
}
}
}
/**
* If one left of both we can match those as well and presto.
*/
if (1 === count($originalTransactions) && 1 === count($transactions)) {
$first = array_shift($originalTransactions);
Log::debug(sprintf('One left of each, link them (ID is #%d)', $first['id']));
$combinations[] = [
'original' => $first,
'submitted' => array_shift($transactions),
];
unset($first);
}
// if they are both empty, we can safely loop all combinations and update them.
if (0 === count($originalTransactions) && 0 === count($transactions)) {
foreach ($combinations as $combination) {
$this->updateCombination($recurrence, $combination);
}
}
// anything left in the original transactions array can be deleted.
foreach ($originalTransactions as $original) {
Log::debug(sprintf('Original transaction #%d is unmatched, delete it!', $original['id']));
$this->deleteTransaction($recurrence, (int)$original['id']);
}
// anything left is new.
$this->createTransactions($recurrence, $transactions);
Log::debug(sprintf('Will delete transaction #%d in recurrence #%d.', $transactionId, $recurrence->id));
$recurrence->recurrenceTransactions()->where('id', $transactionId)->delete();
}
}