Building report from issue #386

This commit is contained in:
James Cole 2016-12-03 21:03:20 +01:00
parent 8377a2a0de
commit b032825342
No known key found for this signature in database
GPG Key ID: C16961E655E74B5E
8 changed files with 148 additions and 105 deletions

View File

@ -52,7 +52,7 @@ class BudgetReportHelper implements BudgetReportHelperInterface
public function getBudgetPeriodReport(Carbon $start, Carbon $end, Collection $accounts): array public function getBudgetPeriodReport(Carbon $start, Carbon $end, Collection $accounts): array
{ {
$budgets = $this->repository->getBudgets(); $budgets = $this->repository->getBudgets();
$report = $this->repository->getBudgetPeriodReport($budgets, $accounts, $start, $end); $report = $this->repository->getBudgetPeriodReport($budgets, $accounts, $start, $end, true);
$data = $this->filterBudgetPeriodReport($report); $data = $this->filterBudgetPeriodReport($report);
return $data; return $data;

View File

@ -209,7 +209,7 @@ class BudgetController extends Controller
// the expenses: // the expenses:
$periods = Navigation::listOfPeriods($start, $end); $periods = Navigation::listOfPeriods($start, $end);
$entries = $repository->getBudgetPeriodReport(new Collection([$budget]), $accounts, $start, $end); $entries = $repository->getBudgetPeriodReport(new Collection([$budget]), $accounts, $start, $end, false);
$budgeted = []; $budgeted = [];
$key = Navigation::preferredCarbonFormat($start, $end); $key = Navigation::preferredCarbonFormat($start, $end);
$range = Navigation::preferredRangeFormat($start, $end); $range = Navigation::preferredRangeFormat($start, $end);

View File

@ -15,11 +15,9 @@ namespace FireflyIII\Http\Controllers\Report;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Helpers\Report\ReportHelperInterface; use FireflyIII\Helpers\Report\ReportHelperInterface;
use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Category; use FireflyIII\Models\Category;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface; use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Support\CacheProperties; use FireflyIII\Support\CacheProperties;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
@ -42,71 +40,15 @@ class CategoryController extends Controller
*/ */
public function categoryPeriodReport(Carbon $start, Carbon $end, Collection $accounts) public function categoryPeriodReport(Carbon $start, Carbon $end, Collection $accounts)
{ {
/** @var CategoryRepositoryInterface $repository */ /** @var CategoryRepositoryInterface $repository */
$repository = app(CategoryRepositoryInterface::class); $repository = app(CategoryRepositoryInterface::class);
$categories = $repository->getCategories(); $categories = $repository->getCategories();
$data = []; $report = $repository->getCategoryPeriodReport($categories, $accounts, $start, $end, true);
$report = $this->filterCategoryPeriodReport($report);
$periods = Navigation::listOfPeriods($start, $end);
// income only: $result = view('reports.partials.category-period', compact('categories', 'periods', 'report'))->render();
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end)
->withOpposingAccount()
->enableInternalFilter()
->setCategories($categories);
$transactions = $collector->getJournals();
// this is the date format we need:
// define period to group on:
$carbonFormat = Navigation::preferredCarbonFormat($start, $end);
// this is the set of transactions for this period
// in these budgets. Now they must be grouped (manually)
// id, period => amount
$income = [];
foreach ($transactions as $transaction) {
$categoryId = max(intval($transaction->transaction_journal_category_id), intval($transaction->transaction_category_id));
$date = $transaction->date->format($carbonFormat);
if (!isset($income[$categoryId])) {
$income[$categoryId]['name'] = $this->getCategoryName($categoryId, $categories);
$income[$categoryId]['sum'] = '0';
$income[$categoryId]['entries'] = [];
}
if (!isset($income[$categoryId]['entries'][$date])) {
$income[$categoryId]['entries'][$date] = '0';
}
$income[$categoryId]['entries'][$date] = bcadd($income[$categoryId]['entries'][$date], $transaction->transaction_amount);
}
// and now the same for stuff without a category:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($start, $end);
$collector->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER]);
$collector->withoutCategory();
$transactions = $collector->getJournals();
$income[0]['entries'] = [];
$income[0]['name'] = strval(trans('firefly.no_category'));
$income[0]['sum'] = '0';
foreach ($transactions as $transaction) {
$date = $transaction->date->format($carbonFormat);
if (!isset($income[0]['entries'][$date])) {
$income[0]['entries'][$date] = '0';
}
$income[0]['entries'][$date] = bcadd($income[0]['entries'][$date], $transaction->transaction_amount);
}
$periods = Navigation::listOfPeriods($start, $end);
$income = $this->filterCategoryPeriodReport($income);
$result = view('reports.partials.category-period', compact('categories', 'periods', 'income'))->render();
return $result; return $result;
} }
@ -148,18 +90,20 @@ class CategoryController extends Controller
*/ */
private function filterCategoryPeriodReport(array $data): array private function filterCategoryPeriodReport(array $data): array
{ {
/** foreach ($data as $key => $set) {
* @var int $categoryId /**
* @var array $set * @var int $categoryId
*/ * @var array $set
foreach ($data as $categoryId => $set) { */
$sum = '0'; foreach ($set as $categoryId => $info) {
foreach ($set['entries'] as $amount) { $sum = '0';
$sum = bcadd($amount, $sum); foreach ($info['entries'] as $amount) {
} $sum = bcadd($amount, $sum);
$data[$categoryId]['sum'] = $sum; }
if (bccomp('0', $sum) === 0) { $data[$key][$categoryId]['sum'] = $sum;
unset($data[$categoryId]); if (bccomp('0', $sum) === 0) {
unset($data[$key][$categoryId]);
}
} }
} }

View File

@ -212,19 +212,18 @@ class BudgetRepository implements BudgetRepositoryInterface
} }
/** /**
* This method is being used to generate the budget overview in the year/multi-year report. More specifically, this * This method is being used to generate the budget overview in the year/multi-year report. Its used
* method runs the query and returns the result that is used for this report. * in both the year/multi-year budget overview AND in the accompanying chart.
*
* The query is used in both the year/multi-year budget overview AND in the accompanying chart.
* *
* @param Collection $budgets * @param Collection $budgets
* @param Collection $accounts * @param Collection $accounts
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param bool $noBudget
* *
* @return array * @return array
*/ */
public function getBudgetPeriodReport(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end): array public function getBudgetPeriodReport(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end, bool $noBudget): array
{ {
$carbonFormat = Navigation::preferredCarbonFormat($start, $end); $carbonFormat = Navigation::preferredCarbonFormat($start, $end);
$data = []; $data = [];
@ -252,8 +251,11 @@ class BudgetRepository implements BudgetRepositoryInterface
$date = $transaction->date->format($carbonFormat); $date = $transaction->date->format($carbonFormat);
$data[$budgetId]['entries'][$date] = bcadd($data[$budgetId]['entries'][$date] ?? '0', $transaction->transaction_amount); $data[$budgetId]['entries'][$date] = bcadd($data[$budgetId]['entries'][$date] ?? '0', $transaction->transaction_amount);
} }
// and now the same for stuff without a budget:
$data[0] = $this->getNoBudgetPeriodReport($start, $end); if ($noBudget) {
// and now the same for stuff without a budget:
$data[0] = $this->getNoBudgetPeriodReport($start, $end);
}
return $data; return $data;

View File

@ -96,10 +96,11 @@ interface BudgetRepositoryInterface
* @param Collection $accounts * @param Collection $accounts
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param bool $noBudget
* *
* @return array * @return array
*/ */
public function getBudgetPeriodReport(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end): array; public function getBudgetPeriodReport(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end, bool $noBudget): array;
/** /**
* @return Collection * @return Collection
@ -119,7 +120,7 @@ interface BudgetRepositoryInterface
* *
* @return string * @return string
*/ */
public function spentInPeriod(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end) : string; public function spentInPeriod(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end): string;
/** /**
* @param Collection $accounts * @param Collection $accounts
@ -143,7 +144,7 @@ interface BudgetRepositoryInterface
* *
* @return Budget * @return Budget
*/ */
public function update(Budget $budget, array $data) : Budget; public function update(Budget $budget, array $data): Budget;
/** /**
* @param Budget $budget * @param Budget $budget
@ -154,6 +155,6 @@ interface BudgetRepositoryInterface
* *
* @return BudgetLimit * @return BudgetLimit
*/ */
public function updateLimitAmount(Budget $budget, Carbon $start, Carbon $end, string $range, int $amount) : BudgetLimit; public function updateLimitAmount(Budget $budget, Carbon $start, Carbon $end, string $range, int $amount): BudgetLimit;
} }

View File

@ -15,12 +15,15 @@ namespace FireflyIII\Repositories\Category;
use Carbon\Carbon; use Carbon\Carbon;
use DB; use DB;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Models\Category; use FireflyIII\Models\Category;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType; use FireflyIII\Models\TransactionType;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Database\Query\JoinClause; use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Navigation;
/** /**
* Class CategoryRepository * Class CategoryRepository
@ -172,6 +175,32 @@ class CategoryRepository implements CategoryRepositoryInterface
return $set; return $set;
} }
/**
* This method is being used to generate the category overview in the year/multi-year report. Its used
* in both the year/multi-year budget overview AND in the accompanying chart.
*
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
* @param @bool $noCategory
*
* @return array
*/
public function getCategoryPeriodReport(Collection $categories, Collection $accounts, Carbon $start, Carbon $end, bool $noCategory): array
{
$data = [
'income' => $this->getCategoryReportData($categories, $accounts, $start, $end, $noCategory, [TransactionType::DEPOSIT, TransactionType::TRANSFER]),
'expense' => $this->getCategoryReportData(
$categories, $accounts, $start, $end, $noCategory, [TransactionType::WITHDRAWAL, TransactionType::TRANSFER]
),
];
return $data;
}
/** /**
* @param Category $category * @param Category $category
* @param Collection $accounts * @param Collection $accounts
@ -233,6 +262,7 @@ class CategoryRepository implements CategoryRepositoryInterface
{ {
$sum = $this->sumInPeriod($categories, $accounts, TransactionType::WITHDRAWAL, $start, $end); $sum = $this->sumInPeriod($categories, $accounts, TransactionType::WITHDRAWAL, $start, $end);
$sum = bcmul($sum, '-1'); $sum = bcmul($sum, '-1');
return $sum; return $sum;
} }
@ -284,6 +314,55 @@ class CategoryRepository implements CategoryRepositoryInterface
return $category; return $category;
} }
/**
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
* @param bool $noCategory
* @param array $types
*
* @return array
*/
private function getCategoryReportData(Collection $categories, Collection $accounts, Carbon $start, Carbon $end, bool $noCategory, array $types): array
{
$carbonFormat = Navigation::preferredCarbonFormat($start, $end);
$data = [];
// prep data array:
/** @var Category $category */
foreach ($categories as $category) {
$data[$category->id] = [
'name' => $category->name,
'sum' => '0',
'entries' => [],
];
}
// get all transactions:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end);
$collector->setCategories($categories)->setTypes($types)
->withOpposingAccount()
->enableInternalFilter();
$transactions = $collector->getJournals();
// loop transactions:
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
$categoryId = max(intval($transaction->transaction_journal_category_id), intval($transaction->transaction_category_id));
$date = $transaction->date->format($carbonFormat);
$data[$categoryId]['entries'][$date] = bcadd($data[$categoryId]['entries'][$date] ?? '0', $transaction->transaction_amount);
}
if ($noCategory) {
// and now the same for stuff without a budget:
//$data[0] = $this->getNoBudgetPeriodReport($start, $end);
}
return $data;
}
/** /**
* @param Collection $categories * @param Collection $categories
* @param Collection $accounts * @param Collection $accounts
@ -404,5 +483,4 @@ class CategoryRepository implements CategoryRepositoryInterface
return $sum; return $sum;
} }
} }

View File

@ -49,7 +49,7 @@ interface CategoryRepositoryInterface
* *
* @return string * @return string
*/ */
public function earnedInPeriodWithoutCategory(Collection $accounts, Carbon $start, Carbon $end) :string; public function earnedInPeriodWithoutCategory(Collection $accounts, Carbon $start, Carbon $end): string;
/** /**
* Find a category * Find a category
@ -58,7 +58,7 @@ interface CategoryRepositoryInterface
* *
* @return Category * @return Category
*/ */
public function find(int $categoryId) : Category; public function find(int $categoryId): Category;
/** /**
* Find a category * Find a category
@ -67,7 +67,7 @@ interface CategoryRepositoryInterface
* *
* @return Category * @return Category
*/ */
public function findByName(string $name) : Category; public function findByName(string $name): Category;
/** /**
* @param Category $category * @param Category $category
@ -83,6 +83,20 @@ interface CategoryRepositoryInterface
*/ */
public function getCategories(): Collection; public function getCategories(): Collection;
/**
* This method is being used to generate the category overview in the year/multi-year report. Its used
* in both the year/multi-year budget overview AND in the accompanying chart.
*
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
* @param bool $noCategory
*
* @return array
*/
public function getCategoryPeriodReport(Collection $categories, Collection $accounts, Carbon $start, Carbon $end, bool $noCategory): array;
/** /**
* Return most recent transaction(journal) date. * Return most recent transaction(journal) date.
* *
@ -110,7 +124,7 @@ interface CategoryRepositoryInterface
* *
* @return string * @return string
*/ */
public function spentInPeriodWithoutCategory(Collection $accounts, Carbon $start, Carbon $end) : string; public function spentInPeriodWithoutCategory(Collection $accounts, Carbon $start, Carbon $end): string;
/** /**
* @param array $data * @param array $data

View File

@ -18,7 +18,7 @@
</thead> </thead>
<tbody> <tbody>
{% for category in categories %} {% for category in categories %}
{% if income[category.id] %} {% if report.income[category.id] or report.expense[category.id] %}
<tr> <tr>
<td data-value="{{ category.name }}"> <td data-value="{{ category.name }}">
<a title="{{ category.name }}" href="#" data-category="{{ category.id }}" class="category-chart-activate">{{ category.name }}</a> <a title="{{ category.name }}" href="#" data-category="{{ category.id }}" class="category-chart-activate">{{ category.name }}</a>
@ -26,26 +26,30 @@
{% for key, period in periods %} {% for key, period in periods %}
{# income first #} {# income first #}
{% if(income[category.id].entries[key]) %} {% if(report.income[category.id].entries[key]) %}
<td data-value="{{ income[category.id].entries[key] }}"> <td data-value="{{ report.income[category.id].entries[key] }}">
{{ income[category.id].entries[key]|formatAmount }} {{ report.income[category.id].entries[key]|formatAmount }}
</td> </td>
{% else %} {% else %}
<td data-value="0"> <td data-value="0">
{{ 0|formatAmount }}
</td> </td>
{% endif %} {% endif %}
{# expenses #} {# expenses #}
<td data-value="0"> {% if(report.expense[category.id].entries[key]) %}
<!-- expense --> <td data-value="{{ report.expense[category.id].entries[key] }}">
</td> {{ report.expense[category.id].entries[key]|formatAmount }}
</td>
{% else %}
<td data-value="0">
</td>
{% endif %}
{% endfor %} {% endfor %}
<td data-value="{{ info.sum }}"> <td data-value="{{ report.income[category.id].sum }}">
0 {{ report.income[category.id].sum }}
</td> </td>
<td data-value="{{ info.sum }}"> <td data-value="{{ report.expense[category.id].sum }}">
1 {{ report.expense[category.id].sum }}
</td> </td>
</tr> </tr>
{% endif %} {% endif %}