diff --git a/app/Http/Controllers/Transaction/ShowController.php b/app/Http/Controllers/Transaction/ShowController.php index c834f492a4..314e08dad5 100644 --- a/app/Http/Controllers/Transaction/ShowController.php +++ b/app/Http/Controllers/Transaction/ShowController.php @@ -192,6 +192,7 @@ class ShowController extends Controller { $amounts = []; foreach ($group['transactions'] as $transaction) { + // add normal amount: $symbol = $transaction['currency_symbol']; $amounts[$symbol] ??= ['amount' => '0', 'symbol' => $symbol, 'decimal_places' => $transaction['currency_decimal_places']]; @@ -212,8 +213,8 @@ class ShowController extends Controller ]; $amounts[$foreignSymbol]['amount'] = bcadd($amounts[$foreignSymbol]['amount'], (string) $transaction['foreign_amount']); } - // add primary currency amount - if (null !== $transaction['pc_amount'] && $transaction['currency_id'] !== $this->primaryCurrency->id) { + // add primary currency amount, but only if it is not the foreign amount or the current one. + if (null !== $transaction['pc_amount'] && $transaction['currency_id'] !== $this->primaryCurrency->id && $transaction['foreign_currency_code'] !== $this->primaryCurrency->code) { // same for foreign currency: $primarySymbol = $this->primaryCurrency->symbol; $amounts[$primarySymbol] ??= [ diff --git a/app/Services/Internal/Support/AccountServiceTrait.php b/app/Services/Internal/Support/AccountServiceTrait.php index 523785366b..18e88621cf 100644 --- a/app/Services/Internal/Support/AccountServiceTrait.php +++ b/app/Services/Internal/Support/AccountServiceTrait.php @@ -27,6 +27,10 @@ namespace FireflyIII\Services\Internal\Support; use Carbon\Carbon; use Deprecated; use FireflyIII\Enums\AccountTypeEnum; +use FireflyIII\Events\Model\TransactionGroup\CreatedSingleTransactionGroup; +use FireflyIII\Events\Model\TransactionGroup\TransactionGroupEventFlags; +use FireflyIII\Events\Model\TransactionGroup\TransactionGroupEventObjects; +use FireflyIII\Events\Model\TransactionGroup\UpdatedSingleTransactionGroup; use FireflyIII\Exceptions\DuplicateTransactionException; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Factory\AccountMetaFactory; @@ -58,8 +62,8 @@ trait AccountServiceTrait if (null === $iban) { return null; } - $data = ['iban' => $iban]; - $rules = ['iban' => 'required|iban']; + $data = ['iban' => $iban]; + $rules = ['iban' => 'required|iban']; $validator = Validator::make($data, $rules); if ($validator->fails()) { Log::info(sprintf('Detected invalid IBAN ("%s"). Return NULL instead.', $iban)); @@ -85,7 +89,7 @@ trait AccountServiceTrait array_key_exists('opening_balance', $data) && '' === $data['opening_balance'] || array_key_exists('opening_balance_date', $data) - && '' === $data['opening_balance_date']; + && '' === $data['opening_balance_date']; } /** @@ -97,14 +101,14 @@ trait AccountServiceTrait */ public function updateMetaData(Account $account, array $data): void { - $fields = $this->validFields; + $fields = $this->validFields; if (AccountTypeEnum::ASSET->value === $account->accountType->type) { $fields = $this->validAssetFields; } // remove currency_id if necessary. - $type = $account->accountType->type; - $list = config('firefly.valid_currency_account_types'); + $type = $account->accountType->type; + $list = config('firefly.valid_currency_account_types'); if (!in_array($type, $list, true)) { $pos = array_search('currency_id', $fields, true); if (false !== $pos) { @@ -146,14 +150,14 @@ trait AccountServiceTrait $data[$field] = $data[$field]->toAtomString(); } - $factory->crud($account, $field, (string) $data[$field]); + $factory->crud($account, $field, (string)$data[$field]); } } } public function updateNote(Account $account, string $note): bool { - $dbNote = $account->notes()->first(); + $dbNote = $account->notes()->first(); if ('' === $note) { $dbNote?->delete(); @@ -174,7 +178,7 @@ trait AccountServiceTrait */ public function validOBData(array $data): bool { - $data['opening_balance'] = (string) ($data['opening_balance'] ?? ''); + $data['opening_balance'] = (string)($data['opening_balance'] ?? ''); if ('' !== $data['opening_balance'] && 0 === bccomp($data['opening_balance'], '0')) { $data['opening_balance'] = ''; } @@ -206,11 +210,11 @@ trait AccountServiceTrait throw new FireflyException('Amount for new liability credit was unexpectedly 0.'); } - $language = Preferences::getForUser($account->user, 'language', 'en_US')->data; + $language = Preferences::getForUser($account->user, 'language', 'en_US')->data; if (is_array($language)) { $language = 'en_US'; } - $language = (string) $language; + $language = (string)$language; // set source and/or destination based on whether the amount is positive or negative. // first, assume the amount is positive and go from there: @@ -224,14 +228,14 @@ trait AccountServiceTrait $sourceId = $account->id; $sourceName = null; $destId = null; - $destName = trans('firefly.liability_credit_description', ['account' => $account->name], $language); + $destName = trans('firefly.liability_credit_description', ['account' => $account->name], $language); } // amount must be positive for the transaction to work. - $amount = Steam::positive($openingBalance); + $amount = Steam::positive($openingBalance); // get or grab currency: - $currency = $this->accountRepository->getAccountCurrency($account); + $currency = $this->accountRepository->getAccountCurrency($account); if (null === $currency) { $currency = Amount::getPrimaryCurrencyByUserGroup($account->user->userGroup); } @@ -241,34 +245,34 @@ trait AccountServiceTrait 'user' => $account->user, 'user_group' => $account->user->userGroup, 'transactions' => [[ - 'type' => 'Liability credit', - 'date' => $openingBalanceDate, - 'source_id' => $sourceId, - 'source_name' => $sourceName, - 'destination_id' => $destId, - 'destination_name' => $destName, - 'user' => $account->user, - 'user_group' => $account->user->userGroup, - 'currency_id' => $currency->id, - 'order' => 0, - 'amount' => $amount, - 'foreign_amount' => null, - 'description' => trans('firefly.liability_credit_description', ['account' => $account->name]), - 'budget_id' => null, - 'budget_name' => null, - 'category_id' => null, - 'category_name' => null, - 'piggy_bank_id' => null, - 'piggy_bank_name' => null, - 'reconciled' => false, - 'notes' => null, - 'tags' => [], - ]], + 'type' => 'Liability credit', + 'date' => $openingBalanceDate, + 'source_id' => $sourceId, + 'source_name' => $sourceName, + 'destination_id' => $destId, + 'destination_name' => $destName, + 'user' => $account->user, + 'user_group' => $account->user->userGroup, + 'currency_id' => $currency->id, + 'order' => 0, + 'amount' => $amount, + 'foreign_amount' => null, + 'description' => trans('firefly.liability_credit_description', ['account' => $account->name]), + 'budget_id' => null, + 'budget_name' => null, + 'category_id' => null, + 'category_name' => null, + 'piggy_bank_id' => null, + 'piggy_bank_name' => null, + 'reconciled' => false, + 'notes' => null, + 'tags' => [], + ]], ]; Log::debug('Going for submission in createCreditTransaction', $submission); /** @var TransactionGroupFactory $factory */ - $factory = app(TransactionGroupFactory::class); + $factory = app(TransactionGroupFactory::class); $factory->setUser($account->user); try { @@ -291,11 +295,11 @@ trait AccountServiceTrait protected function createOBGroup(Account $account, array $data): TransactionGroup { Log::debug('Now going to create an OB group.'); - $language = Preferences::getForUser($account->user, 'language', 'en_US')->data; + $language = Preferences::getForUser($account->user, 'language', 'en_US')->data; if (is_array($language)) { $language = 'en_US'; } - $language = (string) $language; + $language = (string)$language; $sourceId = null; $sourceName = null; $destId = null; @@ -303,29 +307,29 @@ trait AccountServiceTrait $amount = array_key_exists('opening_balance', $data) ? $data['opening_balance'] : '0'; // amount is positive. - if (1 === bccomp((string) $amount, '0')) { + if (1 === bccomp((string)$amount, '0')) { Log::debug(sprintf('Amount is %s, which is positive. Source is a new IB account, destination is #%d', $amount, $account->id)); $sourceName = trans('firefly.initial_balance_description', ['account' => $account->name], $language); $destId = $account->id; } // amount is not positive - if (-1 === bccomp((string) $amount, '0')) { + if (-1 === bccomp((string)$amount, '0')) { Log::debug(sprintf('Amount is %s, which is negative. Destination is a new IB account, source is #%d', $amount, $account->id)); $destName = trans('firefly.initial_balance_account', ['account' => $account->name], $language); $sourceId = $account->id; } // amount is 0 - if (0 === bccomp((string) $amount, '0')) { + if (0 === bccomp((string)$amount, '0')) { Log::debug('Amount is zero, so will not make an OB group.'); throw new FireflyException('Amount for new opening balance was unexpectedly 0.'); } // make amount positive, regardless: - $amount = Steam::positive($amount); + $amount = Steam::positive($amount); // get or grab currency: - $currency = $this->accountRepository->getAccountCurrency($account); + $currency = $this->accountRepository->getAccountCurrency($account); if (null === $currency) { $currency = Amount::getPrimaryCurrencyByUserGroup($account->user->userGroup); } @@ -336,34 +340,34 @@ trait AccountServiceTrait 'user' => $account->user, 'user_group' => $account->user->userGroup, 'transactions' => [[ - 'type' => 'Opening balance', - 'date' => $data['opening_balance_date'], - 'source_id' => $sourceId, - 'source_name' => $sourceName, - 'destination_id' => $destId, - 'destination_name' => $destName, - 'user' => $account->user, - 'user_group' => $account->user->userGroup, - 'currency_id' => $currency->id, - 'order' => 0, - 'amount' => $amount, - 'foreign_amount' => null, - 'description' => trans('firefly.initial_balance_description', ['account' => $account->name]), - 'budget_id' => null, - 'budget_name' => null, - 'category_id' => null, - 'category_name' => null, - 'piggy_bank_id' => null, - 'piggy_bank_name' => null, - 'reconciled' => false, - 'notes' => null, - 'tags' => [], - ]], + 'type' => 'Opening balance', + 'date' => $data['opening_balance_date'], + 'source_id' => $sourceId, + 'source_name' => $sourceName, + 'destination_id' => $destId, + 'destination_name' => $destName, + 'user' => $account->user, + 'user_group' => $account->user->userGroup, + 'currency_id' => $currency->id, + 'order' => 0, + 'amount' => $amount, + 'foreign_amount' => null, + 'description' => trans('firefly.initial_balance_description', ['account' => $account->name]), + 'budget_id' => null, + 'budget_name' => null, + 'category_id' => null, + 'category_name' => null, + 'piggy_bank_id' => null, + 'piggy_bank_name' => null, + 'reconciled' => false, + 'notes' => null, + 'tags' => [], + ]], ]; Log::debug('Going for submission in createOBGroup', $submission); /** @var TransactionGroupFactory $factory */ - $factory = app(TransactionGroupFactory::class); + $factory = app(TransactionGroupFactory::class); $factory->setUser($account->user); try { @@ -384,11 +388,11 @@ trait AccountServiceTrait protected function createOBGroupV2(Account $account, string $openingBalance, Carbon $openingBalanceDate): TransactionGroup { Log::debug('Now going to create an OB group.'); - $language = Preferences::getForUser($account->user, 'language', 'en_US')->data; + $language = Preferences::getForUser($account->user, 'language', 'en_US')->data; if (is_array($language)) { $language = 'en_US'; } - $language = (string) $language; + $language = (string)$language; $sourceId = null; $sourceName = null; $destId = null; @@ -414,10 +418,10 @@ trait AccountServiceTrait } // make amount positive, regardless: - $amount = Steam::positive($openingBalance); + $amount = Steam::positive($openingBalance); // get or grab currency: - $currency = $this->accountRepository->getAccountCurrency($account); + $currency = $this->accountRepository->getAccountCurrency($account); if (null === $currency) { $currency = Amount::getPrimaryCurrencyByUserGroup($account->user->userGroup); } @@ -428,34 +432,34 @@ trait AccountServiceTrait 'user' => $account->user, 'user_group' => $account->user->userGroup, 'transactions' => [[ - 'type' => 'Opening balance', - 'date' => $openingBalanceDate, - 'source_id' => $sourceId, - 'source_name' => $sourceName, - 'destination_id' => $destId, - 'destination_name' => $destName, - 'user' => $account->user, - 'user_group' => $account->user->userGroup, - 'currency_id' => $currency->id, - 'order' => 0, - 'amount' => $amount, - 'foreign_amount' => null, - 'description' => trans('firefly.initial_balance_description', ['account' => $account->name]), - 'budget_id' => null, - 'budget_name' => null, - 'category_id' => null, - 'category_name' => null, - 'piggy_bank_id' => null, - 'piggy_bank_name' => null, - 'reconciled' => false, - 'notes' => null, - 'tags' => [], - ]], + 'type' => 'Opening balance', + 'date' => $openingBalanceDate, + 'source_id' => $sourceId, + 'source_name' => $sourceName, + 'destination_id' => $destId, + 'destination_name' => $destName, + 'user' => $account->user, + 'user_group' => $account->user->userGroup, + 'currency_id' => $currency->id, + 'order' => 0, + 'amount' => $amount, + 'foreign_amount' => null, + 'description' => trans('firefly.initial_balance_description', ['account' => $account->name]), + 'budget_id' => null, + 'budget_name' => null, + 'category_id' => null, + 'category_name' => null, + 'piggy_bank_id' => null, + 'piggy_bank_name' => null, + 'reconciled' => false, + 'notes' => null, + 'tags' => [], + ]], ]; Log::debug('Going for submission in createOBGroupV2', $submission); /** @var TransactionGroupFactory $factory */ - $factory = app(TransactionGroupFactory::class); + $factory = app(TransactionGroupFactory::class); $factory->setUser($account->user); try { @@ -466,6 +470,13 @@ trait AccountServiceTrait throw new FireflyException($e->getMessage(), 0, $e); } + Preferences::mark(); + $objects = TransactionGroupEventObjects::collectFromTransactionGroup($group); + $flags = new TransactionGroupEventFlags(); + $flags->applyRules = false; + $flags->fireWebhooks = false; + $flags->batchSubmission = false; + event(new CreatedSingleTransactionGroup($flags, $objects)); return $group; } @@ -519,10 +530,10 @@ trait AccountServiceTrait { // find currency, or use default currency instead. /** @var TransactionCurrencyFactory $factory */ - $factory = app(TransactionCurrencyFactory::class); + $factory = app(TransactionCurrencyFactory::class); /** @var null|TransactionCurrency $currency */ - $currency = $factory->find($currencyId, $currencyCode); + $currency = $factory->find($currencyId, $currencyCode); if (null === $currency) { // use default currency: @@ -558,7 +569,7 @@ trait AccountServiceTrait } // if direction is "debit" (I owe this debt), amount is negative. // which means the liability will have a negative balance which the user must fill. - $openingBalance = Steam::negative($openingBalance); + $openingBalance = Steam::negative($openingBalance); // if direction is "credit" (I am owed this debt), amount is positive. // which means the liability will have a positive balance which is drained when its paid back into any asset. @@ -567,21 +578,21 @@ trait AccountServiceTrait } // create if not exists: - $clGroup = $this->getCreditTransaction($account); + $clGroup = $this->getCreditTransaction($account); if (null === $clGroup) { return $this->createCreditTransaction($account, $openingBalance, $openingBalanceDate); } // if exists, update: - $currency = $this->accountRepository->getAccountCurrency($account); + $currency = $this->accountRepository->getAccountCurrency($account); if (null === $currency) { $currency = Amount::getPrimaryCurrencyByUserGroup($account->user->userGroup); } // simply grab the first journal and change it: - $journal = $this->getObJournal($clGroup); - $clTransaction = $this->getOBTransaction($journal, $account); - $accountTransaction = $this->getNotOBTransaction($journal, $account); - $journal->date = $openingBalanceDate; + $journal = $this->getObJournal($clGroup); + $clTransaction = $this->getOBTransaction($journal, $account); + $accountTransaction = $this->getNotOBTransaction($journal, $account); + $journal->date = $openingBalanceDate; $journal->transactionCurrency()->associate($currency); // account always gains money: @@ -589,8 +600,8 @@ trait AccountServiceTrait $accountTransaction->transaction_currency_id = $currency->id; // CL account always loses money: - $clTransaction->amount = Steam::negative($openingBalance); - $clTransaction->transaction_currency_id = $currency->id; + $clTransaction->amount = Steam::negative($openingBalance); + $clTransaction->transaction_currency_id = $currency->id; // save both $accountTransaction->save(); $clTransaction->save(); @@ -610,14 +621,14 @@ trait AccountServiceTrait { Log::debug(sprintf('Now in %s', __METHOD__)); // create if not exists: - $obGroup = $this->getOBGroup($account); + $obGroup = $this->getOBGroup($account); if (null === $obGroup) { return $this->createOBGroupV2($account, $openingBalance, $openingBalanceDate); } Log::debug('Update OB group'); // if exists, update: - $currency = $this->accountRepository->getAccountCurrency($account); + $currency = $this->accountRepository->getAccountCurrency($account); if (null === $currency) { $currency = Amount::getPrimaryCurrencyByUserGroup($account->user->userGroup); } @@ -637,8 +648,8 @@ trait AccountServiceTrait $accountTransaction->transaction_currency_id = $currency->id; // OB account transaction gains money - $obTransaction->amount = Steam::positive($openingBalance); - $obTransaction->transaction_currency_id = $currency->id; + $obTransaction->amount = Steam::positive($openingBalance); + $obTransaction->transaction_currency_id = $currency->id; } if (-1 === bccomp('0', $openingBalance)) { Log::debug('Amount is positive.'); @@ -647,8 +658,8 @@ trait AccountServiceTrait $accountTransaction->transaction_currency_id = $currency->id; // OB account loses money: - $obTransaction->amount = Steam::negative($openingBalance); - $obTransaction->transaction_currency_id = $currency->id; + $obTransaction->amount = Steam::negative($openingBalance); + $obTransaction->transaction_currency_id = $currency->id; } // save both $accountTransaction->save(); @@ -656,6 +667,13 @@ trait AccountServiceTrait $journal->save(); $obGroup->refresh(); + $objects = TransactionGroupEventObjects::collectFromTransactionGroup($obGroup); + $flags = new TransactionGroupEventFlags(); + $flags->applyRules = false; + $flags->fireWebhooks = false; + $flags->batchSubmission = false; + event(new UpdatedSingleTransactionGroup($flags, $objects)); + return $obGroup; } diff --git a/resources/views/list/groups.twig b/resources/views/list/groups.twig index ccb43f7820..88f7d59662 100644 --- a/resources/views/list/groups.twig +++ b/resources/views/list/groups.twig @@ -260,8 +260,8 @@ {% if null != transaction.foreign_amount %} ({{ formatAmountBySymbol(transaction.foreign_amount, transaction.foreign_currency_symbol, transaction.foreign_currency_decimal_places) }}) {% endif %} - {# primary currency amount of withdrawal #} - {% if convertToPrimary and 0 != transaction.pc_amount %} + {# primary currency amount of withdrawal, if not in foreign currency #} + {% if convertToPrimary and 0 != transaction.pc_amount and primaryCurrency.id != transaction.foreign_currency_id %} ({{ formatAmountBySymbol(transaction.pc_amount, primaryCurrency.symbol, primaryCurrency.decimal_places) }}) {% endif %} {% endif %} @@ -304,9 +304,9 @@ {% endif %} {% elseif transaction.transaction_type_type == 'Opening balance' %} {% if account.id == transaction.source_account_id %} - {{ formatAmountBySymbol(transaction.destination_balance_after, transaction.currency_symbol, transaction.currency_decimal_places) }} - {% elseif account.id == transaction.destination_account_id %} {{ formatAmountBySymbol(transaction.source_balance_after, transaction.currency_symbol, transaction.currency_decimal_places) }} + {% elseif account.id == transaction.destination_account_id %} + {{ formatAmountBySymbol(transaction.destination_balance_after, transaction.currency_symbol, transaction.currency_decimal_places) }} {% else %} - {% endif %} diff --git a/resources/views/transactions/show.twig b/resources/views/transactions/show.twig index a0c6eab04a..080faf17cf 100644 --- a/resources/views/transactions/show.twig +++ b/resources/views/transactions/show.twig @@ -315,8 +315,8 @@ {% endif %} - - {% if null != journal.pc_amount and primaryCurrency.id != journal.currency_id %} + + {% if null != journal.pc_amount and primaryCurrency.id != journal.currency_id and primaryCurrency.id != journal.foreign_currency_id %} {% if first.transaction_type_type == 'Withdrawal' %} ({{ formatAmountBySymbol(journal.pc_amount, primaryCurrency.symbol, primaryCurrency.decimal_places) }}) {% elseif first.transaction_type_type == 'Deposit' %}