mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-10-12 23:45:10 +00:00
Report fixes for #2418
This commit is contained in:
@@ -188,6 +188,46 @@ class GroupCollector implements GroupCollectorInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define which accounts can be part of the source and destination transactions.
|
||||||
|
*
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return GroupCollectorInterface
|
||||||
|
*/
|
||||||
|
public function setSourceAccounts(Collection $accounts): GroupCollectorInterface
|
||||||
|
{
|
||||||
|
if ($accounts->count() > 0) {
|
||||||
|
$accountIds = $accounts->pluck('id')->toArray();
|
||||||
|
$this->query->whereIn('source.account_id', $accountIds);
|
||||||
|
|
||||||
|
app('log')->debug(sprintf('GroupCollector: setSourceAccounts: %s', implode(', ', $accountIds)));
|
||||||
|
$this->accountIds = $accountIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define which accounts can be part of the source and destination transactions.
|
||||||
|
*
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return GroupCollectorInterface
|
||||||
|
*/
|
||||||
|
public function setDestinationAccounts(Collection $accounts): GroupCollectorInterface
|
||||||
|
{
|
||||||
|
if ($accounts->count() > 0) {
|
||||||
|
$accountIds = $accounts->pluck('id')->toArray();
|
||||||
|
$this->query->whereIn('destination.account_id', $accountIds);
|
||||||
|
|
||||||
|
app('log')->debug(sprintf('GroupCollector: setSourceAccounts: %s', implode(', ', $accountIds)));
|
||||||
|
$this->accountIds = $accountIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Limit the search to a specific bill.
|
* Limit the search to a specific bill.
|
||||||
*
|
*
|
||||||
@@ -1010,4 +1050,44 @@ class GroupCollector implements GroupCollectorInterface
|
|||||||
->orderBy('transaction_journals.description', 'DESC')
|
->orderBy('transaction_journals.description', 'DESC')
|
||||||
->orderBy('source.amount', 'DESC');
|
->orderBy('source.amount', 'DESC');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These accounts must not be source accounts.
|
||||||
|
*
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return GroupCollectorInterface
|
||||||
|
*/
|
||||||
|
public function excludeSourceAccounts(Collection $accounts): GroupCollectorInterface
|
||||||
|
{
|
||||||
|
if ($accounts->count() > 0) {
|
||||||
|
$accountIds = $accounts->pluck('id')->toArray();
|
||||||
|
$this->query->whereNotIn('source.account_id', $accountIds);
|
||||||
|
|
||||||
|
app('log')->debug(sprintf('GroupCollector: excludeSourceAccounts: %s', implode(', ', $accountIds)));
|
||||||
|
$this->accountIds = $accountIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These accounts must not be destination accounts.
|
||||||
|
*
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return GroupCollectorInterface
|
||||||
|
*/
|
||||||
|
public function excludeDestinationAccounts(Collection $accounts): GroupCollectorInterface
|
||||||
|
{
|
||||||
|
if ($accounts->count() > 0) {
|
||||||
|
$accountIds = $accounts->pluck('id')->toArray();
|
||||||
|
$this->query->whereNotIn('destination.account_id', $accountIds);
|
||||||
|
|
||||||
|
app('log')->debug(sprintf('GroupCollector: excludeDestinationAccounts: %s', implode(', ', $accountIds)));
|
||||||
|
$this->accountIds = $accountIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
@@ -46,6 +46,41 @@ interface GroupCollectorInterface
|
|||||||
*/
|
*/
|
||||||
public function getExtractedJournals(): array;
|
public function getExtractedJournals(): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set source accounts.
|
||||||
|
*
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return GroupCollectorInterface
|
||||||
|
*/
|
||||||
|
public function setSourceAccounts(Collection $accounts): GroupCollectorInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These accounts must not be source accounts.
|
||||||
|
*
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return GroupCollectorInterface
|
||||||
|
*/
|
||||||
|
public function excludeSourceAccounts(Collection $accounts): GroupCollectorInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exclude destination accounts.
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return GroupCollectorInterface
|
||||||
|
*/
|
||||||
|
public function excludeDestinationAccounts(Collection $accounts): GroupCollectorInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set destination accounts.
|
||||||
|
*
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return GroupCollectorInterface
|
||||||
|
*/
|
||||||
|
public function setDestinationAccounts(Collection $accounts): GroupCollectorInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the sum of all journals.
|
* Return the sum of all journals.
|
||||||
*
|
*
|
||||||
|
@@ -155,7 +155,7 @@ class OperationsController extends Controller
|
|||||||
$incomeSum = array_sum(
|
$incomeSum = array_sum(
|
||||||
array_map(
|
array_map(
|
||||||
static function ($item) {
|
static function ($item) {
|
||||||
return bcmul($item['sum'], '-1');
|
return $item['sum'];
|
||||||
},
|
},
|
||||||
$incomes
|
$incomes
|
||||||
)
|
)
|
||||||
|
@@ -133,11 +133,12 @@ class AccountTasker implements AccountTaskerInterface
|
|||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
|
|
||||||
$collector->setAccounts($accounts)->setRange($start, $end);
|
$collector->setSourceAccounts($accounts)->setRange($start, $end);
|
||||||
|
$collector->excludeDestinationAccounts($accounts);
|
||||||
$collector->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
|
$collector->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
|
||||||
->withAccountInformation();
|
->withAccountInformation();
|
||||||
$journals = $collector->getExtractedJournals();
|
$journals = $collector->getExtractedJournals();
|
||||||
$expenses = $this->groupByDestination($journals);
|
$expenses = $this->groupExpenseByDestination($journals);
|
||||||
|
|
||||||
// sort the result
|
// sort the result
|
||||||
// Obtain a list of columns
|
// Obtain a list of columns
|
||||||
@@ -166,11 +167,11 @@ class AccountTasker implements AccountTaskerInterface
|
|||||||
|
|
||||||
/** @var GroupCollectorInterface $collector */
|
/** @var GroupCollectorInterface $collector */
|
||||||
$collector = app(GroupCollectorInterface::class);
|
$collector = app(GroupCollectorInterface::class);
|
||||||
|
$collector->setDestinationAccounts($accounts)->setRange($start, $end);
|
||||||
$collector->setAccounts($accounts)->setRange($start, $end);
|
$collector->excludeSourceAccounts($accounts);
|
||||||
$collector->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])
|
$collector->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])
|
||||||
->withAccountInformation();
|
->withAccountInformation();
|
||||||
$income = $this->groupByDestination($collector->getExtractedJournals());
|
$income = $this->groupIncomeBySource($collector->getExtractedJournals());
|
||||||
|
|
||||||
// sort the result
|
// sort the result
|
||||||
// Obtain a list of columns
|
// Obtain a list of columns
|
||||||
@@ -196,9 +197,8 @@ class AccountTasker implements AccountTaskerInterface
|
|||||||
* @param array $array
|
* @param array $array
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
|
||||||
*/
|
*/
|
||||||
private function groupByDestination(array $array): array
|
private function groupExpenseByDestination(array $array): array
|
||||||
{
|
{
|
||||||
$defaultCurrency = app('amount')->getDefaultCurrencyByUser($this->user);
|
$defaultCurrency = app('amount')->getDefaultCurrencyByUser($this->user);
|
||||||
/** @var CurrencyRepositoryInterface $currencyRepos */
|
/** @var CurrencyRepositoryInterface $currencyRepos */
|
||||||
@@ -207,18 +207,18 @@ class AccountTasker implements AccountTaskerInterface
|
|||||||
$expenses = [];
|
$expenses = [];
|
||||||
$countAccounts = []; // if count remains 0 use original name, not the name with the currency.
|
$countAccounts = []; // if count remains 0 use original name, not the name with the currency.
|
||||||
|
|
||||||
|
|
||||||
/** @var array $journal */
|
/** @var array $journal */
|
||||||
foreach ($array as $journal) {
|
foreach ($array as $journal) {
|
||||||
$opposingId = (int)$journal['destination_account_id'];
|
$destinationId = (int)$journal['destination_account_id'];
|
||||||
$currencyId = (int)$journal['currency_id'];
|
$currencyId = (int)$journal['currency_id'];
|
||||||
$key = sprintf('%s-%s', $opposingId, $currencyId);
|
$key = sprintf('%s-%s', $destinationId, $currencyId);
|
||||||
$name = sprintf('%s (%s)', $journal['destination_account_name'], $journal['currency_name']);
|
$name = sprintf('%s (%s)', $journal['destination_account_name'], $journal['currency_name']);
|
||||||
$countAccounts[$opposingId] = isset($countAccounts[$opposingId]) ? $countAccounts[$opposingId] + 1 : 1;
|
$countAccounts[$destinationId] = isset($countAccounts[$destinationId]) ? $countAccounts[$destinationId] + 1 : 1;
|
||||||
|
|
||||||
if (!isset($expenses[$key])) {
|
if (!isset($expenses[$key])) {
|
||||||
$currencies[$currencyId] = $currencies[$currencyId] ?? $currencyRepos->findNull($currencyId);
|
$currencies[$currencyId] = $currencies[$currencyId] ?? $currencyRepos->findNull($currencyId);
|
||||||
$expenses[$key] = [
|
$expenses[$key] = [
|
||||||
'id' => $opposingId,
|
'id' => $destinationId,
|
||||||
'name' => $name,
|
'name' => $name,
|
||||||
'original' => $journal['destination_account_name'],
|
'original' => $journal['destination_account_name'],
|
||||||
'sum' => '0',
|
'sum' => '0',
|
||||||
@@ -232,6 +232,7 @@ class AccountTasker implements AccountTaskerInterface
|
|||||||
$expenses[$key]['sum'] = bcadd($expenses[$key]['sum'], $journal['amount']);
|
$expenses[$key]['sum'] = bcadd($expenses[$key]['sum'], $journal['amount']);
|
||||||
++$expenses[$key]['count'];
|
++$expenses[$key]['count'];
|
||||||
}
|
}
|
||||||
|
|
||||||
// do averages:
|
// do averages:
|
||||||
$keys = array_keys($expenses);
|
$keys = array_keys($expenses);
|
||||||
foreach ($keys as $key) {
|
foreach ($keys as $key) {
|
||||||
@@ -249,4 +250,62 @@ class AccountTasker implements AccountTaskerInterface
|
|||||||
|
|
||||||
return $expenses;
|
return $expenses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $array
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function groupIncomeBySource(array $array): array
|
||||||
|
{
|
||||||
|
$defaultCurrency = app('amount')->getDefaultCurrencyByUser($this->user);
|
||||||
|
/** @var CurrencyRepositoryInterface $currencyRepos */
|
||||||
|
$currencyRepos = app(CurrencyRepositoryInterface::class);
|
||||||
|
$currencies = [$defaultCurrency->id => $defaultCurrency,];
|
||||||
|
$income = [];
|
||||||
|
$countAccounts = []; // if count remains 0 use original name, not the name with the currency.
|
||||||
|
|
||||||
|
/** @var array $journal */
|
||||||
|
foreach ($array as $journal) {
|
||||||
|
$sourceId = (int)$journal['source_account_id'];
|
||||||
|
$currencyId = (int)$journal['currency_id'];
|
||||||
|
$key = sprintf('%s-%s', $sourceId, $currencyId);
|
||||||
|
$name = sprintf('%s (%s)', $journal['source_account_name'], $journal['currency_name']);
|
||||||
|
$countAccounts[$sourceId] = isset($countAccounts[$sourceId]) ? $countAccounts[$sourceId] + 1 : 1;
|
||||||
|
|
||||||
|
if (!isset($income[$key])) {
|
||||||
|
$currencies[$currencyId] = $currencies[$currencyId] ?? $currencyRepos->findNull($currencyId);
|
||||||
|
$income[$key] = [
|
||||||
|
'id' => $sourceId,
|
||||||
|
'name' => $name,
|
||||||
|
'original' => $journal['source_account_name'],
|
||||||
|
'sum' => '0',
|
||||||
|
'average' => '0',
|
||||||
|
'currencies' => [],
|
||||||
|
'single_currency' => $currencies[$currencyId],
|
||||||
|
'count' => 0,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$income[$key]['currencies'][] = (int)$journal['currency_id'];
|
||||||
|
$income[$key]['sum'] = bcadd($income[$key]['sum'], bcmul($journal['amount'], '-1'));
|
||||||
|
++$income[$key]['count'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// do averages:
|
||||||
|
$keys = array_keys($income);
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
$opposingId = $income[$key]['id'];
|
||||||
|
if (1 === $countAccounts[$opposingId]) {
|
||||||
|
$income[$key]['name'] = $income[$key]['original'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($income[$key]['count'] > 1) {
|
||||||
|
$income[$key]['average'] = bcdiv($income[$key]['sum'], (string)$income[$key]['count']);
|
||||||
|
}
|
||||||
|
$income[$key]['currencies'] = count(array_unique($income[$key]['currencies']));
|
||||||
|
$income[$key]['all_currencies'] = count($currencies);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $income;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user