mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-12-12 01:42:32 +00:00
🤖 Auto commit for release 'develop' on 2025-05-11
This commit is contained in:
@@ -39,8 +39,8 @@ class CorrectsUnevenAmount extends Command
|
||||
{
|
||||
use ShowsFriendlyMessages;
|
||||
|
||||
protected $description = 'Fix journals with uneven amounts.';
|
||||
protected $signature = 'correction:uneven-amounts';
|
||||
protected $description = 'Fix journals with uneven amounts.';
|
||||
protected $signature = 'correction:uneven-amounts';
|
||||
private int $count;
|
||||
|
||||
/**
|
||||
@@ -71,17 +71,18 @@ class CorrectsUnevenAmount extends Command
|
||||
Log::debug('convertOldStyleTransfers()');
|
||||
// select transactions with a foreign amount and a foreign currency. and it's a transfer. and they are different.
|
||||
$transactions = Transaction::distinct()
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', 'transactions.transaction_journal_id')
|
||||
->leftJoin('transaction_types', 'transaction_types.id', 'transaction_journals.transaction_type_id')
|
||||
->where('transaction_types.type', TransactionTypeEnum::TRANSFER->value)
|
||||
->whereNotNull('foreign_currency_id')
|
||||
->whereNotNull('foreign_amount')->get(['transactions.transaction_journal_id']);
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', 'transactions.transaction_journal_id')
|
||||
->leftJoin('transaction_types', 'transaction_types.id', 'transaction_journals.transaction_type_id')
|
||||
->where('transaction_types.type', TransactionTypeEnum::TRANSFER->value)
|
||||
->whereNotNull('foreign_currency_id')
|
||||
->whereNotNull('foreign_amount')->get(['transactions.transaction_journal_id'])
|
||||
;
|
||||
$count = 0;
|
||||
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($transactions as $transaction) {
|
||||
/** @var null|TransactionJournal $journal */
|
||||
$journal = TransactionJournal::find($transaction->transaction_journal_id);
|
||||
$journal = TransactionJournal::find($transaction->transaction_journal_id);
|
||||
if (null === $journal) {
|
||||
Log::debug('Found no journal, continue.');
|
||||
|
||||
@@ -98,7 +99,7 @@ class CorrectsUnevenAmount extends Command
|
||||
$destination = $journal->transactions()->where('amount', '>', 0)->first();
|
||||
|
||||
/** @var null|Transaction $source */
|
||||
$source = $journal->transactions()->where('amount', '<', 0)->first();
|
||||
$source = $journal->transactions()->where('amount', '<', 0)->first();
|
||||
if (null === $destination || null === $source) {
|
||||
Log::debug('Source or destination transaction is NULL, continue.');
|
||||
|
||||
@@ -129,9 +130,10 @@ class CorrectsUnevenAmount extends Command
|
||||
{
|
||||
Log::debug('fixUnevenAmounts()');
|
||||
$journals = DB::table('transactions')
|
||||
->groupBy('transaction_journal_id')
|
||||
->whereNull('deleted_at')
|
||||
->get(['transaction_journal_id', DB::raw('SUM(amount) AS the_sum')]);
|
||||
->groupBy('transaction_journal_id')
|
||||
->whereNull('deleted_at')
|
||||
->get(['transaction_journal_id', DB::raw('SUM(amount) AS the_sum')])
|
||||
;
|
||||
|
||||
/** @var \stdClass $entry */
|
||||
foreach ($journals as $entry) {
|
||||
@@ -169,13 +171,13 @@ class CorrectsUnevenAmount extends Command
|
||||
private function fixJournal(int $param): void
|
||||
{
|
||||
// one of the transactions is bad.
|
||||
$journal = TransactionJournal::find($param);
|
||||
$journal = TransactionJournal::find($param);
|
||||
if (null === $journal) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var null|Transaction $source */
|
||||
$source = $journal->transactions()->where('amount', '<', 0)->first();
|
||||
$source = $journal->transactions()->where('amount', '<', 0)->first();
|
||||
|
||||
if (null === $source) {
|
||||
$this->friendlyError(
|
||||
@@ -192,11 +194,11 @@ class CorrectsUnevenAmount extends Command
|
||||
return;
|
||||
}
|
||||
|
||||
$amount = bcmul('-1', (string) $source->amount);
|
||||
$amount = bcmul('-1', (string) $source->amount);
|
||||
|
||||
// fix amount of destination:
|
||||
/** @var null|Transaction $destination */
|
||||
$destination = $journal->transactions()->where('amount', '>', 0)->first();
|
||||
$destination = $journal->transactions()->where('amount', '>', 0)->first();
|
||||
|
||||
if (null === $destination) {
|
||||
$this->friendlyError(
|
||||
@@ -221,7 +223,7 @@ class CorrectsUnevenAmount extends Command
|
||||
return;
|
||||
}
|
||||
|
||||
$message = sprintf('Sum of journal #%d is not zero, journal is broken and now fixed.', $journal->id);
|
||||
$message = sprintf('Sum of journal #%d is not zero, journal is broken and now fixed.', $journal->id);
|
||||
|
||||
$this->friendlyWarning($message);
|
||||
app('log')->warning($message);
|
||||
@@ -229,7 +231,7 @@ class CorrectsUnevenAmount extends Command
|
||||
$destination->amount = $amount;
|
||||
$destination->save();
|
||||
|
||||
$message = sprintf('Corrected amount in transaction journal #%d', $param);
|
||||
$message = sprintf('Corrected amount in transaction journal #%d', $param);
|
||||
$this->friendlyInfo($message);
|
||||
++$this->count;
|
||||
}
|
||||
@@ -244,7 +246,7 @@ class CorrectsUnevenAmount extends Command
|
||||
$destination = $journal->transactions()->where('amount', '>', 0)->first();
|
||||
|
||||
/** @var Transaction $source */
|
||||
$source = $journal->transactions()->where('amount', '<', 0)->first();
|
||||
$source = $journal->transactions()->where('amount', '<', 0)->first();
|
||||
|
||||
// safety catch on NULL should not be necessary, we just had that catch.
|
||||
// source amount = dest foreign amount
|
||||
@@ -271,10 +273,11 @@ class CorrectsUnevenAmount extends Command
|
||||
private function matchCurrencies(): void
|
||||
{
|
||||
$journals = TransactionJournal::leftJoin('transactions', 'transaction_journals.id', 'transactions.transaction_journal_id')
|
||||
->where('transactions.transaction_currency_id', '!=', DB::raw('transaction_journals.transaction_currency_id'))
|
||||
->get(['transaction_journals.*']);
|
||||
->where('transactions.transaction_currency_id', '!=', DB::raw('transaction_journals.transaction_currency_id'))
|
||||
->get(['transaction_journals.*'])
|
||||
;
|
||||
|
||||
$count = 0;
|
||||
$count = 0;
|
||||
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($journals as $journal) {
|
||||
@@ -296,37 +299,44 @@ class CorrectsUnevenAmount extends Command
|
||||
private function isBetweenAssetAndLiability(TransactionJournal $journal): bool
|
||||
{
|
||||
/** @var Transaction $sourceTransaction */
|
||||
$sourceTransaction = $journal->transactions()->where('amount', '<', 0)->first();
|
||||
$sourceTransaction = $journal->transactions()->where('amount', '<', 0)->first();
|
||||
|
||||
/** @var Transaction $destinationTransaction */
|
||||
$destinationTransaction = $journal->transactions()->where('amount', '>', 0)->first();
|
||||
if (null === $sourceTransaction || null === $destinationTransaction) {
|
||||
Log::warning('Either transaction is false, stop.');
|
||||
|
||||
return false;
|
||||
}
|
||||
if (null === $sourceTransaction->foreign_amount || null === $destinationTransaction->foreign_amount) {
|
||||
Log::warning('Either foreign amount is false, stop.');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$source = $sourceTransaction->account;
|
||||
$destination = $destinationTransaction->account;
|
||||
$source = $sourceTransaction->account;
|
||||
$destination = $destinationTransaction->account;
|
||||
|
||||
if (null === $source || null === $destination) {
|
||||
Log::warning('Either is false, stop.');
|
||||
|
||||
return false;
|
||||
}
|
||||
$sourceTypes = [AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value];
|
||||
$sourceTypes = [AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value];
|
||||
|
||||
// source is liability, destination is asset
|
||||
if (in_array($source->accountType->type, $sourceTypes, true) && AccountTypeEnum::ASSET->value === $destination->accountType->type) {
|
||||
Log::debug('Source is a liability account, destination is an asset account, return TRUE.');
|
||||
|
||||
return true;
|
||||
}
|
||||
// source is asset, destination is liability
|
||||
if (in_array($destination->accountType->type, $sourceTypes, true) && AccountTypeEnum::ASSET->value === $source->accountType->type) {
|
||||
Log::debug('Destination is a liability account, source is an asset account, return TRUE.');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -334,24 +344,25 @@ class CorrectsUnevenAmount extends Command
|
||||
{
|
||||
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
Log::debug('convertOldStyleTransactions()');
|
||||
$count = 0;
|
||||
$transactions = Transaction::distinct()
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', 'transactions.transaction_journal_id')
|
||||
->leftJoin('transaction_types', 'transaction_types.id', 'transaction_journals.transaction_type_id')
|
||||
->leftJoin('accounts', 'accounts.id', 'transactions.account_id')
|
||||
->leftJoin('account_types', 'account_types.id', 'accounts.account_type_id')
|
||||
->whereNot('transaction_types.type', TransactionTypeEnum::TRANSFER->value)
|
||||
->whereNotNull('foreign_currency_id')
|
||||
->whereNotNull('foreign_amount')
|
||||
->whereIn('account_types.type', [AccountTypeEnum::ASSET->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::LOAN->value])
|
||||
->get(['transactions.transaction_journal_id']);
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', 'transactions.transaction_journal_id')
|
||||
->leftJoin('transaction_types', 'transaction_types.id', 'transaction_journals.transaction_type_id')
|
||||
->leftJoin('accounts', 'accounts.id', 'transactions.account_id')
|
||||
->leftJoin('account_types', 'account_types.id', 'accounts.account_type_id')
|
||||
->whereNot('transaction_types.type', TransactionTypeEnum::TRANSFER->value)
|
||||
->whereNotNull('foreign_currency_id')
|
||||
->whereNotNull('foreign_amount')
|
||||
->whereIn('account_types.type', [AccountTypeEnum::ASSET->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::LOAN->value])
|
||||
->get(['transactions.transaction_journal_id'])
|
||||
;
|
||||
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($transactions as $transaction) {
|
||||
/** @var null|TransactionJournal $journal */
|
||||
$journal = TransactionJournal::find($transaction->transaction_journal_id);
|
||||
$journal = TransactionJournal::find($transaction->transaction_journal_id);
|
||||
$repository->setUser($journal->user);
|
||||
if (null === $journal) {
|
||||
Log::debug('Found no journal, continue.');
|
||||
@@ -391,10 +402,10 @@ class CorrectsUnevenAmount extends Command
|
||||
$source->foreign_currency_id = $currency;
|
||||
$source->saveQuietly();
|
||||
$source->refresh();
|
||||
// Log::debug(sprintf('source->amount = %s', $source->amount));
|
||||
// Log::debug(sprintf('source->transaction_currency_id = %s', $source->transaction_currency_id));
|
||||
// Log::debug(sprintf('source->foreign_amount = %s', $source->foreign_amount));
|
||||
// Log::debug(sprintf('source->foreign_currency_id = %s', $source->foreign_currency_id));
|
||||
// Log::debug(sprintf('source->amount = %s', $source->amount));
|
||||
// Log::debug(sprintf('source->transaction_currency_id = %s', $source->transaction_currency_id));
|
||||
// Log::debug(sprintf('source->foreign_amount = %s', $source->foreign_amount));
|
||||
// Log::debug(sprintf('source->foreign_currency_id = %s', $source->foreign_currency_id));
|
||||
++$count;
|
||||
}
|
||||
// same but for destination
|
||||
@@ -411,23 +422,23 @@ class CorrectsUnevenAmount extends Command
|
||||
$destination->balance_dirty = true;
|
||||
$destination->saveQuietly();
|
||||
$destination->refresh();
|
||||
// Log::debug(sprintf('destination->amount = %s', $destination->amount));
|
||||
// Log::debug(sprintf('destination->transaction_currency_id = %s', $destination->transaction_currency_id));
|
||||
// Log::debug(sprintf('destination->foreign_amount = %s', $destination->foreign_amount));
|
||||
// Log::debug(sprintf('destination->foreign_currency_id = %s', $destination->foreign_currency_id));
|
||||
// Log::debug(sprintf('destination->amount = %s', $destination->amount));
|
||||
// Log::debug(sprintf('destination->transaction_currency_id = %s', $destination->transaction_currency_id));
|
||||
// Log::debug(sprintf('destination->foreign_amount = %s', $destination->foreign_amount));
|
||||
// Log::debug(sprintf('destination->foreign_currency_id = %s', $destination->foreign_currency_id));
|
||||
}
|
||||
|
||||
|
||||
// // only fix the destination transaction
|
||||
// $destination->foreign_currency_id = $source->transaction_currency_id;
|
||||
// $destination->foreign_amount = app('steam')->positive($source->amount);
|
||||
// $destination->transaction_currency_id = $source->foreign_currency_id;
|
||||
// $destination->amount = app('steam')->positive($source->foreign_amount);
|
||||
// $destination->balance_dirty = true;
|
||||
// $source->balance_dirty = true;
|
||||
// $destination->save();
|
||||
// $source->save();
|
||||
// $this->friendlyWarning(sprintf('Corrected foreign amounts of transaction #%d.', $journal->id));
|
||||
// // only fix the destination transaction
|
||||
// $destination->foreign_currency_id = $source->transaction_currency_id;
|
||||
// $destination->foreign_amount = app('steam')->positive($source->amount);
|
||||
// $destination->transaction_currency_id = $source->foreign_currency_id;
|
||||
// $destination->amount = app('steam')->positive($source->foreign_amount);
|
||||
// $destination->balance_dirty = true;
|
||||
// $source->balance_dirty = true;
|
||||
// $destination->save();
|
||||
// $source->save();
|
||||
// $this->friendlyWarning(sprintf('Corrected foreign amounts of transaction #%d.', $journal->id));
|
||||
}
|
||||
if (0 === $count) {
|
||||
return;
|
||||
|
||||
@@ -104,7 +104,7 @@ class TransactionJournalFactory
|
||||
{
|
||||
Log::debug('Now in TransactionJournalFactory::create()');
|
||||
// convert to special object.
|
||||
$dataObject = new NullArrayObject($data);
|
||||
$dataObject = new NullArrayObject($data);
|
||||
|
||||
Log::debug('Start of TransactionJournalFactory::create()');
|
||||
$collection = new Collection();
|
||||
@@ -163,18 +163,18 @@ class TransactionJournalFactory
|
||||
$this->errorIfDuplicate($row['import_hash_v2']);
|
||||
|
||||
// Some basic fields
|
||||
$type = $this->typeRepository->findTransactionType(null, $row['type']);
|
||||
$carbon = $row['date'] ?? today(config('app.timezone'));
|
||||
$order = $row['order'] ?? 0;
|
||||
$type = $this->typeRepository->findTransactionType(null, $row['type']);
|
||||
$carbon = $row['date'] ?? today(config('app.timezone'));
|
||||
$order = $row['order'] ?? 0;
|
||||
|
||||
Log::debug('Find currency or return default.');
|
||||
$currency = $this->currencyRepository->findCurrency((int) $row['currency_id'], $row['currency_code']);
|
||||
$currency = $this->currencyRepository->findCurrency((int) $row['currency_id'], $row['currency_code']);
|
||||
Log::debug('Find foreign currency or return NULL.');
|
||||
|
||||
$foreignCurrency = $this->currencyRepository->findCurrencyNull($row['foreign_currency_id'], $row['foreign_currency_code']);
|
||||
$bill = $this->billRepository->findBill((int) $row['bill_id'], $row['bill_name']);
|
||||
$billId = TransactionTypeEnum::WITHDRAWAL->value === $type->type && null !== $bill ? $bill->id : null;
|
||||
$description = (string) $row['description'];
|
||||
$foreignCurrency = $this->currencyRepository->findCurrencyNull($row['foreign_currency_id'], $row['foreign_currency_code']);
|
||||
$bill = $this->billRepository->findBill((int) $row['bill_id'], $row['bill_name']);
|
||||
$billId = TransactionTypeEnum::WITHDRAWAL->value === $type->type && null !== $bill ? $bill->id : null;
|
||||
$description = (string) $row['description'];
|
||||
|
||||
// Manipulate basic fields
|
||||
$carbon->setTimezone(config('app.timezone'));
|
||||
@@ -196,7 +196,7 @@ class TransactionJournalFactory
|
||||
}
|
||||
|
||||
/** create or get source and destination accounts */
|
||||
$sourceInfo = [
|
||||
$sourceInfo = [
|
||||
'id' => $row['source_id'],
|
||||
'name' => $row['source_name'],
|
||||
'iban' => $row['source_iban'],
|
||||
@@ -205,7 +205,7 @@ class TransactionJournalFactory
|
||||
'currency_id' => $currency->id,
|
||||
];
|
||||
|
||||
$destInfo = [
|
||||
$destInfo = [
|
||||
'id' => $row['destination_id'],
|
||||
'name' => $row['destination_name'],
|
||||
'iban' => $row['destination_iban'],
|
||||
@@ -215,8 +215,8 @@ class TransactionJournalFactory
|
||||
];
|
||||
Log::debug('Source info:', $sourceInfo);
|
||||
Log::debug('Destination info:', $destInfo);
|
||||
$sourceAccount = $this->getAccount($type->type, 'source', $sourceInfo);
|
||||
$destinationAccount = $this->getAccount($type->type, 'destination', $destInfo);
|
||||
$sourceAccount = $this->getAccount($type->type, 'source', $sourceInfo);
|
||||
$destinationAccount = $this->getAccount($type->type, 'destination', $destInfo);
|
||||
Log::debug('Done with getAccount(2x)');
|
||||
|
||||
|
||||
@@ -225,16 +225,16 @@ class TransactionJournalFactory
|
||||
[$sourceAccount, $destinationAccount] = $this->reconciliationSanityCheck($sourceAccount, $destinationAccount);
|
||||
}
|
||||
|
||||
$currency = $this->getCurrencyByAccount($type->type, $currency, $sourceAccount, $destinationAccount);
|
||||
$foreignCurrency = $this->compareCurrencies($currency, $foreignCurrency);
|
||||
$foreignCurrency = $this->getForeignByAccount($type->type, $foreignCurrency, $destinationAccount);
|
||||
$description = $this->getDescription($description);
|
||||
$currency = $this->getCurrencyByAccount($type->type, $currency, $sourceAccount, $destinationAccount);
|
||||
$foreignCurrency = $this->compareCurrencies($currency, $foreignCurrency);
|
||||
$foreignCurrency = $this->getForeignByAccount($type->type, $foreignCurrency, $destinationAccount);
|
||||
$description = $this->getDescription($description);
|
||||
|
||||
Log::debug(sprintf('Currency is #%d "%s", foreign currency is #%d "%s"', $currency->id, $currency->code, $foreignCurrency?->id, $foreignCurrency));
|
||||
Log::debug(sprintf('Date: %s (%s)', $carbon->toW3cString(), $carbon->getTimezone()->getName()));
|
||||
|
||||
/** Create a basic journal. */
|
||||
$journal = TransactionJournal::create(
|
||||
$journal = TransactionJournal::create(
|
||||
[
|
||||
'user_id' => $this->user->id,
|
||||
'user_group_id' => $this->userGroup->id,
|
||||
@@ -252,7 +252,7 @@ class TransactionJournalFactory
|
||||
Log::debug(sprintf('Created new journal #%d: "%s"', $journal->id, $journal->description));
|
||||
|
||||
/** Create two transactions. */
|
||||
$transactionFactory = app(TransactionFactory::class);
|
||||
$transactionFactory = app(TransactionFactory::class);
|
||||
$transactionFactory->setJournal($journal);
|
||||
$transactionFactory->setAccount($sourceAccount);
|
||||
$transactionFactory->setCurrency($currency);
|
||||
@@ -270,7 +270,7 @@ class TransactionJournalFactory
|
||||
}
|
||||
|
||||
/** @var TransactionFactory $transactionFactory */
|
||||
$transactionFactory = app(TransactionFactory::class);
|
||||
$transactionFactory = app(TransactionFactory::class);
|
||||
$transactionFactory->setJournal($journal);
|
||||
$transactionFactory->setAccount($destinationAccount);
|
||||
$transactionFactory->setAccountInformation($destInfo);
|
||||
@@ -282,10 +282,10 @@ class TransactionJournalFactory
|
||||
// Firefly III will save the foreign currency information in such a way that both
|
||||
// asset accounts can look at the "amount" and "transaction_currency_id" column and
|
||||
// see the currency they expect to see.
|
||||
$amount = (string) $row['amount'];
|
||||
$foreignAmount = (string) $row['foreign_amount'];
|
||||
if (null !== $foreignCurrency && $foreignCurrency->id !== $currency->id &&
|
||||
(TransactionTypeEnum::TRANSFER->value === $type->type || $this->isBetweenAssetAndLiability($sourceAccount, $destinationAccount))
|
||||
$amount = (string) $row['amount'];
|
||||
$foreignAmount = (string) $row['foreign_amount'];
|
||||
if (null !== $foreignCurrency && $foreignCurrency->id !== $currency->id
|
||||
&& (TransactionTypeEnum::TRANSFER->value === $type->type || $this->isBetweenAssetAndLiability($sourceAccount, $destinationAccount))
|
||||
) {
|
||||
$transactionFactory->setCurrency($foreignCurrency);
|
||||
$transactionFactory->setForeignCurrency($currency);
|
||||
@@ -303,7 +303,7 @@ class TransactionJournalFactory
|
||||
|
||||
throw new FireflyException($e->getMessage(), 0, $e);
|
||||
}
|
||||
$journal->completed = true;
|
||||
$journal->completed = true;
|
||||
$journal->save();
|
||||
$this->storeBudget($journal, $row);
|
||||
$this->storeCategory($journal, $row);
|
||||
@@ -328,7 +328,7 @@ class TransactionJournalFactory
|
||||
Log::error(sprintf('Could not encode dataRow: %s', $e->getMessage()));
|
||||
$json = microtime();
|
||||
}
|
||||
$hash = hash('sha256', $json);
|
||||
$hash = hash('sha256', $json);
|
||||
Log::debug(sprintf('The hash is: %s', $hash), $dataRow);
|
||||
|
||||
return $hash;
|
||||
@@ -349,12 +349,13 @@ class TransactionJournalFactory
|
||||
|
||||
/** @var null|TransactionJournalMeta $result */
|
||||
$result = TransactionJournalMeta::withTrashed()
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id')
|
||||
->whereNotNull('transaction_journals.id')
|
||||
->where('transaction_journals.user_id', $this->user->id)
|
||||
->where('data', \Safe\json_encode($hash, JSON_THROW_ON_ERROR))
|
||||
->with(['transactionJournal', 'transactionJournal.transactionGroup'])
|
||||
->first(['journal_meta.*']);
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id')
|
||||
->whereNotNull('transaction_journals.id')
|
||||
->where('transaction_journals.user_id', $this->user->id)
|
||||
->where('data', \Safe\json_encode($hash, JSON_THROW_ON_ERROR))
|
||||
->with(['transactionJournal', 'transactionJournal.transactionGroup'])
|
||||
->first(['journal_meta.*'])
|
||||
;
|
||||
if (null !== $result) {
|
||||
Log::warning(sprintf('Found a duplicate in errorIfDuplicate because hash %s is not unique!', $hash));
|
||||
$journal = $result->transactionJournal()->withTrashed()->first();
|
||||
@@ -371,18 +372,18 @@ class TransactionJournalFactory
|
||||
private function validateAccounts(NullArrayObject $data): void
|
||||
{
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
$transactionType = $data['type'] ?? 'invalid';
|
||||
$transactionType = $data['type'] ?? 'invalid';
|
||||
$this->accountValidator->setUser($this->user);
|
||||
$this->accountValidator->setTransactionType($transactionType);
|
||||
|
||||
// validate source account.
|
||||
$array = [
|
||||
$array = [
|
||||
'id' => null !== $data['source_id'] ? (int) $data['source_id'] : null,
|
||||
'name' => null !== $data['source_name'] ? (string) $data['source_name'] : null,
|
||||
'iban' => null !== $data['source_iban'] ? (string) $data['source_iban'] : null,
|
||||
'number' => null !== $data['source_number'] ? (string) $data['source_number'] : null,
|
||||
];
|
||||
$validSource = $this->accountValidator->validateSource($array);
|
||||
$validSource = $this->accountValidator->validateSource($array);
|
||||
|
||||
// do something with result:
|
||||
if (false === $validSource) {
|
||||
@@ -391,7 +392,7 @@ class TransactionJournalFactory
|
||||
Log::debug('Source seems valid.');
|
||||
|
||||
// validate destination account
|
||||
$array = [
|
||||
$array = [
|
||||
'id' => null !== $data['destination_id'] ? (int) $data['destination_id'] : null,
|
||||
'name' => null !== $data['destination_name'] ? (string) $data['destination_name'] : null,
|
||||
'iban' => null !== $data['destination_iban'] ? (string) $data['destination_iban'] : null,
|
||||
@@ -483,7 +484,7 @@ class TransactionJournalFactory
|
||||
// return user's default:
|
||||
return app('amount')->getNativeCurrencyByUserGroup($this->user->userGroup);
|
||||
}
|
||||
$result = $preference ?? $currency;
|
||||
$result = $preference ?? $currency;
|
||||
Log::debug(sprintf('Currency is now #%d (%s) because of account #%d (%s)', $result->id, $result->code, $account->id, $account->name));
|
||||
|
||||
return $result;
|
||||
@@ -573,7 +574,7 @@ class TransactionJournalFactory
|
||||
|
||||
protected function storeMeta(TransactionJournal $journal, NullArrayObject $data, string $field): void
|
||||
{
|
||||
$set = [
|
||||
$set = [
|
||||
'journal' => $journal,
|
||||
'name' => $field,
|
||||
'data' => (string) ($data[$field] ?? ''),
|
||||
@@ -628,16 +629,19 @@ class TransactionJournalFactory
|
||||
$sourceTypes = [AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value];
|
||||
|
||||
// source is liability, destination is asset
|
||||
if(in_array($source->accountType->type, $sourceTypes, true) && AccountTypeEnum::ASSET->value === $destination->accountType->type) {
|
||||
if (in_array($source->accountType->type, $sourceTypes, true) && AccountTypeEnum::ASSET->value === $destination->accountType->type) {
|
||||
Log::debug('Source is a liability account, destination is an asset account, return TRUE.');
|
||||
|
||||
return true;
|
||||
}
|
||||
// source is asset, destination is liability
|
||||
if(in_array($destination->accountType->type, $sourceTypes, true) && AccountTypeEnum::ASSET->value === $source->accountType->type) {
|
||||
if (in_array($destination->accountType->type, $sourceTypes, true) && AccountTypeEnum::ASSET->value === $source->accountType->type) {
|
||||
Log::debug('Destination is a liability account, source is an asset account, return TRUE.');
|
||||
|
||||
return true;
|
||||
}
|
||||
Log::debug('Not between asset and liability, return FALSE');
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ class Kernel extends HttpKernel
|
||||
// full API authentication
|
||||
'api' => [
|
||||
AcceptHeaders::class,
|
||||
// EnsureFrontendRequestsAreStateful::class,
|
||||
// EnsureFrontendRequestsAreStateful::class,
|
||||
'auth:api,sanctum',
|
||||
'bindings',
|
||||
],
|
||||
|
||||
@@ -50,15 +50,15 @@ class ReturnsAvailableChannels
|
||||
private static function returnOwnerChannels(): array
|
||||
{
|
||||
|
||||
$channels = ['mail'];
|
||||
if(true === config('notifications.channels.slack.enabled', false)) {
|
||||
$channels = ['mail'];
|
||||
if (true === config('notifications.channels.slack.enabled', false)) {
|
||||
$slackUrl = app('fireflyconfig')->getEncrypted('slack_webhook_url', '')->data;
|
||||
if (UrlValidator::isValidWebhookURL($slackUrl)) {
|
||||
$channels[] = 'slack';
|
||||
}
|
||||
}
|
||||
|
||||
if(true === config('notifications.channels.ntfy.enabled', false)) {
|
||||
if (true === config('notifications.channels.ntfy.enabled', false)) {
|
||||
// validate presence of of Ntfy settings.
|
||||
if ('' !== (string) app('fireflyconfig')->getEncrypted('ntfy_topic', '')->data) {
|
||||
Log::debug('Enabled ntfy.');
|
||||
@@ -70,7 +70,7 @@ class ReturnsAvailableChannels
|
||||
}
|
||||
|
||||
// pushover
|
||||
if(true === config('notifications.channels.pushover.enabled', false)) {
|
||||
if (true === config('notifications.channels.pushover.enabled', false)) {
|
||||
$pushoverAppToken = (string) app('fireflyconfig')->getEncrypted('pushover_app_token', '')->data;
|
||||
$pushoverUserToken = (string) app('fireflyconfig')->getEncrypted('pushover_user_token', '')->data;
|
||||
if ('' === $pushoverAppToken || '' === $pushoverUserToken) {
|
||||
@@ -90,9 +90,9 @@ class ReturnsAvailableChannels
|
||||
private static function returnUserChannels(User $user): array
|
||||
{
|
||||
Log::debug(sprintf('Checking channels for user #%d', $user->id));
|
||||
$channels = ['mail'];
|
||||
$channels = ['mail'];
|
||||
|
||||
if(true === config('notifications.channels.slack.enabled', false)) {
|
||||
if (true === config('notifications.channels.slack.enabled', false)) {
|
||||
$slackUrl = (string) app('preferences')->getEncryptedForUser($user, 'slack_webhook_url', '')->data;
|
||||
if (UrlValidator::isValidWebhookURL($slackUrl)) {
|
||||
$channels[] = 'slack';
|
||||
@@ -100,7 +100,7 @@ class ReturnsAvailableChannels
|
||||
}
|
||||
|
||||
// validate presence of of Ntfy settings.
|
||||
if(true === config('notifications.channels.nfy.enabled', false)) {
|
||||
if (true === config('notifications.channels.nfy.enabled', false)) {
|
||||
$ntfyTopic = (string) app('preferences')->getEncryptedForUser($user, 'ntfy_topic', '')->data;
|
||||
if ('' !== $ntfyTopic) {
|
||||
Log::debug(sprintf('Enabled ntfy, "%s"', $ntfyTopic));
|
||||
@@ -112,7 +112,7 @@ class ReturnsAvailableChannels
|
||||
}
|
||||
|
||||
// pushover
|
||||
if(true === config('notifications.channels.slack.enabled', false)) {
|
||||
if (true === config('notifications.channels.slack.enabled', false)) {
|
||||
$pushoverAppToken = (string) app('preferences')->getEncryptedForUser($user, 'pushover_app_token', '')->data;
|
||||
$pushoverUserToken = (string) app('preferences')->getEncryptedForUser($user, 'pushover_user_token', '')->data;
|
||||
if ('' === $pushoverAppToken || '' === $pushoverUserToken) {
|
||||
|
||||
@@ -79,7 +79,7 @@ class AccountEnrichment implements EnrichmentInterface
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function enrichSingle(array | Model $model): Account | array
|
||||
public function enrichSingle(array|Model $model): Account|array
|
||||
{
|
||||
Log::debug(__METHOD__);
|
||||
$collection = new Collection([$model]);
|
||||
@@ -133,9 +133,10 @@ class AccountEnrichment implements EnrichmentInterface
|
||||
|
||||
private function collectMetaData(): void
|
||||
{
|
||||
$set = AccountMeta::whereIn('name', ['is_multi_currency', 'include_net_worth', 'currency_id', 'account_role', 'account_number', 'BIC', 'liability_direction', 'interest', 'interest_period', 'current_debt'])
|
||||
->whereIn('account_id', $this->accountIds)
|
||||
->get(['account_meta.id', 'account_meta.account_id', 'account_meta.name', 'account_meta.data'])->toArray();
|
||||
$set = AccountMeta::whereIn('name', ['is_multi_currency', 'include_net_worth', 'currency_id', 'account_role', 'account_number', 'BIC', 'liability_direction', 'interest', 'interest_period', 'current_debt'])
|
||||
->whereIn('account_id', $this->accountIds)
|
||||
->get(['account_meta.id', 'account_meta.account_id', 'account_meta.name', 'account_meta.data'])->toArray()
|
||||
;
|
||||
|
||||
/** @var array $entry */
|
||||
foreach ($set as $entry) {
|
||||
@@ -144,7 +145,7 @@ class AccountEnrichment implements EnrichmentInterface
|
||||
$this->currencies[(int) $entry['data']] = true;
|
||||
}
|
||||
}
|
||||
$currencies = TransactionCurrency::whereIn('id', array_keys($this->currencies))->get();
|
||||
$currencies = TransactionCurrency::whereIn('id', array_keys($this->currencies))->get();
|
||||
foreach ($currencies as $currency) {
|
||||
$this->currencies[(int) $currency->id] = $currency;
|
||||
}
|
||||
@@ -159,9 +160,10 @@ class AccountEnrichment implements EnrichmentInterface
|
||||
private function collectNotes(): void
|
||||
{
|
||||
$notes = Note::query()->whereIn('noteable_id', $this->accountIds)
|
||||
->whereNotNull('notes.text')
|
||||
->where('notes.text', '!=', '')
|
||||
->where('noteable_type', Account::class)->get(['notes.noteable_id', 'notes.text'])->toArray();
|
||||
->whereNotNull('notes.text')
|
||||
->where('notes.text', '!=', '')
|
||||
->where('noteable_type', Account::class)->get(['notes.noteable_id', 'notes.text'])->toArray()
|
||||
;
|
||||
foreach ($notes as $note) {
|
||||
$this->notes[(int) $note['noteable_id']] = (string) $note['text'];
|
||||
}
|
||||
@@ -171,14 +173,15 @@ class AccountEnrichment implements EnrichmentInterface
|
||||
private function collectLocations(): void
|
||||
{
|
||||
$locations = Location::query()->whereIn('locatable_id', $this->accountIds)
|
||||
->where('locatable_type', Account::class)->get(['locations.locatable_id', 'locations.latitude', 'locations.longitude', 'locations.zoom_level'])->toArray();
|
||||
->where('locatable_type', Account::class)->get(['locations.locatable_id', 'locations.latitude', 'locations.longitude', 'locations.zoom_level'])->toArray()
|
||||
;
|
||||
foreach ($locations as $location) {
|
||||
$this->locations[(int) $location['locatable_id']]
|
||||
= [
|
||||
'latitude' => (float) $location['latitude'],
|
||||
'longitude' => (float) $location['longitude'],
|
||||
'zoom_level' => (int) $location['zoom_level'],
|
||||
];
|
||||
'latitude' => (float) $location['latitude'],
|
||||
'longitude' => (float) $location['longitude'],
|
||||
'zoom_level' => (int) $location['zoom_level'],
|
||||
];
|
||||
}
|
||||
Log::debug(sprintf('Enrich with %d locations(s)', count($this->locations)));
|
||||
}
|
||||
@@ -193,19 +196,20 @@ class AccountEnrichment implements EnrichmentInterface
|
||||
->setUserGroup($this->userGroup)
|
||||
->setAccounts($this->collection)
|
||||
->withAccountInformation()
|
||||
->setTypes([TransactionTypeEnum::OPENING_BALANCE->value]);
|
||||
$journals = $collector->getExtractedJournals();
|
||||
->setTypes([TransactionTypeEnum::OPENING_BALANCE->value])
|
||||
;
|
||||
$journals = $collector->getExtractedJournals();
|
||||
foreach ($journals as $journal) {
|
||||
$this->openingBalances[(int) $journal['source_account_id']]
|
||||
= [
|
||||
'amount' => Steam::negative($journal['amount']),
|
||||
'date' => $journal['date'],
|
||||
];
|
||||
'amount' => Steam::negative($journal['amount']),
|
||||
'date' => $journal['date'],
|
||||
];
|
||||
$this->openingBalances[(int) $journal['destination_account_id']]
|
||||
= [
|
||||
'amount' => Steam::positive($journal['amount']),
|
||||
'date' => $journal['date'],
|
||||
];
|
||||
'amount' => Steam::positive($journal['amount']),
|
||||
'date' => $journal['date'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,7 +232,7 @@ class AccountEnrichment implements EnrichmentInterface
|
||||
$notes = $this->notes;
|
||||
$openingBalances = $this->openingBalances;
|
||||
$locations = $this->locations;
|
||||
$lastActivities = $this->lastActivities;
|
||||
$lastActivities = $this->lastActivities;
|
||||
$this->collection = $this->collection->map(function (Account $item) use ($accountTypes, $meta, $currencies, $notes, $openingBalances, $locations, $lastActivities) {
|
||||
$item->full_account_type = $accountTypes[(int) $item->account_type_id] ?? null;
|
||||
$accountMeta = [
|
||||
@@ -267,7 +271,7 @@ class AccountEnrichment implements EnrichmentInterface
|
||||
if (array_key_exists($item->id, $lastActivities)) {
|
||||
$accountMeta['last_activity'] = $lastActivities[$item->id];
|
||||
}
|
||||
$item->meta = $accountMeta;
|
||||
$item->meta = $accountMeta;
|
||||
|
||||
return $item;
|
||||
});
|
||||
|
||||
@@ -152,7 +152,7 @@ class AccountTransformer extends AbstractTransformer
|
||||
'longitude' => $longitude,
|
||||
'latitude' => $latitude,
|
||||
'zoom_level' => $zoomLevel,
|
||||
'last_activity' => array_key_exists('last_activity', $account->meta) ? $account->meta['last_activity']->toAtomString() : null,
|
||||
'last_activity' => array_key_exists('last_activity', $account->meta) ? $account->meta['last_activity']->toAtomString() : null,
|
||||
'links' => [
|
||||
[
|
||||
'rel' => 'self',
|
||||
|
||||
@@ -234,7 +234,7 @@ trait TransactionValidation
|
||||
return;
|
||||
}
|
||||
Log::debug(sprintf('Source account expects #%d: %s', $sourceCurrency->id, $sourceCurrency->code));
|
||||
Log::debug(sprintf('Destination account expects #%d: %s', $destinationCurrency->id, $destinationCurrency->code));
|
||||
Log::debug(sprintf('Destination account expects #%d: %s', $destinationCurrency->id, $destinationCurrency->code));
|
||||
|
||||
Log::debug(sprintf('Amount is %s', $transaction['amount']));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user