mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-10-18 10:16:49 +00:00
Fix #7810
This commit is contained in:
@@ -182,11 +182,14 @@ class CreditRecalculateService
|
|||||||
*/
|
*/
|
||||||
private function processWorkAccount(Account $account): void
|
private function processWorkAccount(Account $account): void
|
||||||
{
|
{
|
||||||
|
app('log')->debug(sprintf('Now processing account #%d ("%s")', $account->id, $account->name));
|
||||||
// get opening balance (if present)
|
// get opening balance (if present)
|
||||||
$this->repository->setUser($account->user);
|
$this->repository->setUser($account->user);
|
||||||
$startOfDebt = $this->repository->getOpeningBalanceAmount($account) ?? '0';
|
$startOfDebt = $this->repository->getOpeningBalanceAmount($account) ?? '0';
|
||||||
$leftOfDebt = app('steam')->positive($startOfDebt);
|
$leftOfDebt = app('steam')->positive($startOfDebt);
|
||||||
|
|
||||||
|
app('log')->debug(sprintf('Start of debt is "%s", so initial left of debt is "%s"', $startOfDebt, $leftOfDebt));
|
||||||
|
|
||||||
/** @var AccountMetaFactory $factory */
|
/** @var AccountMetaFactory $factory */
|
||||||
$factory = app(AccountMetaFactory::class);
|
$factory = app(AccountMetaFactory::class);
|
||||||
|
|
||||||
@@ -196,13 +199,22 @@ class CreditRecalculateService
|
|||||||
// get direction of liability:
|
// get direction of liability:
|
||||||
$direction = (string)$this->repository->getMetaValue($account, 'liability_direction');
|
$direction = (string)$this->repository->getMetaValue($account, 'liability_direction');
|
||||||
|
|
||||||
|
app('log')->debug(sprintf('Debt direction is "%s"', $direction));
|
||||||
|
|
||||||
// now loop all transactions (except opening balance and credit thing)
|
// now loop all transactions (except opening balance and credit thing)
|
||||||
$transactions = $account->transactions()->get();
|
$transactions = $account->transactions()
|
||||||
|
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||||
|
->orderBy('transaction_journals.date', 'ASC')
|
||||||
|
->get(['transactions.*']);
|
||||||
|
$total = $transactions->count();
|
||||||
|
app('log')->debug(sprintf('Found %d transaction(s) to process.', $total));
|
||||||
/** @var Transaction $transaction */
|
/** @var Transaction $transaction */
|
||||||
foreach ($transactions as $transaction) {
|
foreach ($transactions as $index => $transaction) {
|
||||||
|
app('log')->debug(sprintf('[%d/%d] Processing transaction.', $index + 1, $total));
|
||||||
$leftOfDebt = $this->processTransaction($account, $direction, $transaction, $leftOfDebt);
|
$leftOfDebt = $this->processTransaction($account, $direction, $transaction, $leftOfDebt);
|
||||||
}
|
}
|
||||||
$factory->crud($account, 'current_debt', $leftOfDebt);
|
$factory->crud($account, 'current_debt', $leftOfDebt);
|
||||||
|
app('log')->debug(sprintf('Done processing account #%d ("%s")', $account->id, $account->name));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -215,6 +227,7 @@ class CreditRecalculateService
|
|||||||
*/
|
*/
|
||||||
private function processTransaction(Account $account, string $direction, Transaction $transaction, string $leftOfDebt): string
|
private function processTransaction(Account $account, string $direction, Transaction $transaction, string $leftOfDebt): string
|
||||||
{
|
{
|
||||||
|
app('log')->debug(sprintf('Left of debt is: %s', $leftOfDebt));
|
||||||
$journal = $transaction->transactionJournal;
|
$journal = $transaction->transactionJournal;
|
||||||
$foreignCurrency = $transaction->foreignCurrency;
|
$foreignCurrency = $transaction->foreignCurrency;
|
||||||
$accountCurrency = $this->repository->getAccountCurrency($account);
|
$accountCurrency = $this->repository->getAccountCurrency($account);
|
||||||
@@ -226,16 +239,20 @@ class CreditRecalculateService
|
|||||||
$sourceTransaction = $journal->transactions()->where('amount', '<', '0')->first();
|
$sourceTransaction = $journal->transactions()->where('amount', '<', '0')->first();
|
||||||
|
|
||||||
if ('' === $direction) {
|
if ('' === $direction) {
|
||||||
|
app('log')->warning('Direction is empty, so do nothing.');
|
||||||
return $leftOfDebt;
|
return $leftOfDebt;
|
||||||
}
|
}
|
||||||
if (TransactionType::LIABILITY_CREDIT === $type || TransactionType::OPENING_BALANCE === $type) {
|
if (TransactionType::LIABILITY_CREDIT === $type || TransactionType::OPENING_BALANCE === $type) {
|
||||||
|
app('log')->warning(sprintf('Transaction type is "%s", so do nothing.', $type));
|
||||||
return $leftOfDebt;
|
return $leftOfDebt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// amount to use depends on the currency:
|
// amount to use depends on the currency:
|
||||||
$usedAmount = $transaction->amount;
|
$usedAmount = $transaction->amount;
|
||||||
|
app('log')->debug(sprintf('Amount of transaction is %s', $usedAmount));
|
||||||
if (null !== $foreignCurrency && $foreignCurrency->id === $accountCurrency->id) {
|
if (null !== $foreignCurrency && $foreignCurrency->id === $accountCurrency->id) {
|
||||||
$usedAmount = $transaction->foreign_amount;
|
$usedAmount = $transaction->foreign_amount;
|
||||||
|
app('log')->debug(sprintf('Overruled by foreign amount. Amount of transaction is now %s', $usedAmount));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Case 1
|
// Case 1
|
||||||
@@ -248,7 +265,10 @@ class CreditRecalculateService
|
|||||||
&& 1 === bccomp($usedAmount, '0')
|
&& 1 === bccomp($usedAmount, '0')
|
||||||
&& 'credit' === $direction
|
&& 'credit' === $direction
|
||||||
) {
|
) {
|
||||||
return bcadd($leftOfDebt, app('steam')->positive($usedAmount));
|
$usedAmount = app('steam')->positive($usedAmount);
|
||||||
|
$result = bcadd($leftOfDebt, $usedAmount);
|
||||||
|
app('log')->debug(sprintf('Case 1 (withdrawal into credit liability): %s + %s = %s', $leftOfDebt, $usedAmount, $result));
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Case 2
|
// Case 2
|
||||||
@@ -261,7 +281,10 @@ class CreditRecalculateService
|
|||||||
&& -1 === bccomp($usedAmount, '0')
|
&& -1 === bccomp($usedAmount, '0')
|
||||||
&& 'credit' === $direction
|
&& 'credit' === $direction
|
||||||
) {
|
) {
|
||||||
return bcsub($leftOfDebt, app('steam')->positive($usedAmount));
|
$usedAmount = app('steam')->positive($usedAmount);
|
||||||
|
$result = bcsub($leftOfDebt, $usedAmount);
|
||||||
|
app('log')->debug(sprintf('Case 2 (withdrawal away from liability): %s - %s = %s', $leftOfDebt, $usedAmount, $result));
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// case 3
|
// case 3
|
||||||
@@ -274,7 +297,10 @@ class CreditRecalculateService
|
|||||||
&& -1 === bccomp($usedAmount, '0')
|
&& -1 === bccomp($usedAmount, '0')
|
||||||
&& 'credit' === $direction
|
&& 'credit' === $direction
|
||||||
) {
|
) {
|
||||||
return bcsub($leftOfDebt, app('steam')->positive($usedAmount));
|
$usedAmount = app('steam')->positive($usedAmount);
|
||||||
|
$result = bcsub($leftOfDebt, $usedAmount);
|
||||||
|
app('log')->debug(sprintf('Case 3 (deposit away from liability): %s - %s = %s', $leftOfDebt, $usedAmount, $result));
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// case 4
|
// case 4
|
||||||
@@ -287,14 +313,32 @@ class CreditRecalculateService
|
|||||||
&& 1 === bccomp($usedAmount, '0')
|
&& 1 === bccomp($usedAmount, '0')
|
||||||
&& 'credit' === $direction
|
&& 'credit' === $direction
|
||||||
) {
|
) {
|
||||||
$newLeftOfDebt = bcadd($leftOfDebt, app('steam')->positive($usedAmount));
|
$usedAmount = app('steam')->positive($usedAmount);
|
||||||
return $newLeftOfDebt;
|
$result = bcadd($leftOfDebt, $usedAmount);
|
||||||
|
app('log')->debug(sprintf('Case 4 (deposit into credit liability): %s + %s = %s', $leftOfDebt, $usedAmount, $result));
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
// case 5: transfer into loan (from other loan).
|
||||||
|
// if it's a credit ("I am owed") this increases the amount due,
|
||||||
|
// because the person has to pay more back.
|
||||||
|
if (
|
||||||
|
$type === TransactionType::TRANSFER
|
||||||
|
&& (int)$account->id === (int)$destTransaction->account_id
|
||||||
|
&& 1 === bccomp($usedAmount, '0')
|
||||||
|
&& 'credit' === $direction
|
||||||
|
) {
|
||||||
|
$usedAmount = app('steam')->positive($usedAmount);
|
||||||
|
$result = bcadd($leftOfDebt, $usedAmount);
|
||||||
|
app('log')->debug(sprintf('Case 5 (transfer into credit liability): %s + %s = %s', $leftOfDebt, $usedAmount, $result));
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// in any other case, remove amount from left of debt.
|
// in any other case, remove amount from left of debt.
|
||||||
if (in_array($type, [TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER], true)) {
|
if (in_array($type, [TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER], true)) {
|
||||||
$newLeftOfDebt = bcadd($leftOfDebt, bcmul($usedAmount, '-1'));
|
$usedAmount = app('steam')->negative($usedAmount);
|
||||||
return $newLeftOfDebt;
|
$result = bcadd($leftOfDebt, $usedAmount);
|
||||||
|
app('log')->debug(sprintf('Case X (all other cases): %s + %s = %s', $leftOfDebt, $usedAmount, $result));
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log::warning(sprintf('[6] Catch-all, should not happen. Left of debt = %s', $leftOfDebt));
|
Log::warning(sprintf('[6] Catch-all, should not happen. Left of debt = %s', $leftOfDebt));
|
||||||
|
Reference in New Issue
Block a user