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
{
$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);
return $data;

View File

@ -209,7 +209,7 @@ class BudgetController extends Controller
// the expenses:
$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 = [];
$key = Navigation::preferredCarbonFormat($start, $end);
$range = Navigation::preferredRangeFormat($start, $end);

View File

@ -15,11 +15,9 @@ namespace FireflyIII\Http\Controllers\Report;
use Carbon\Carbon;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Helpers\Report\ReportHelperInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Category;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Support\CacheProperties;
use Illuminate\Support\Collection;
@ -42,71 +40,15 @@ class CategoryController extends Controller
*/
public function categoryPeriodReport(Carbon $start, Carbon $end, Collection $accounts)
{
/** @var CategoryRepositoryInterface $repository */
$repository = app(CategoryRepositoryInterface::class);
$categories = $repository->getCategories();
$data = [];
$report = $repository->getCategoryPeriodReport($categories, $accounts, $start, $end, true);
$report = $this->filterCategoryPeriodReport($report);
$periods = Navigation::listOfPeriods($start, $end);
// income only:
/** @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();
$result = view('reports.partials.category-period', compact('categories', 'periods', 'report'))->render();
return $result;
}
@ -148,18 +90,20 @@ class CategoryController extends Controller
*/
private function filterCategoryPeriodReport(array $data): array
{
/**
* @var int $categoryId
* @var array $set
*/
foreach ($data as $categoryId => $set) {
$sum = '0';
foreach ($set['entries'] as $amount) {
$sum = bcadd($amount, $sum);
}
$data[$categoryId]['sum'] = $sum;
if (bccomp('0', $sum) === 0) {
unset($data[$categoryId]);
foreach ($data as $key => $set) {
/**
* @var int $categoryId
* @var array $set
*/
foreach ($set as $categoryId => $info) {
$sum = '0';
foreach ($info['entries'] as $amount) {
$sum = bcadd($amount, $sum);
}
$data[$key][$categoryId]['sum'] = $sum;
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
* method runs the query and returns the result that is used for this report.
*
* The query is used in both the year/multi-year budget overview AND in the accompanying chart.
* This method is being used to generate the budget overview in the year/multi-year report. Its used
* in both the year/multi-year budget overview AND in the accompanying chart.
*
* @param Collection $budgets
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
* @param bool $noBudget
*
* @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);
$data = [];
@ -252,8 +251,11 @@ class BudgetRepository implements BudgetRepositoryInterface
$date = $transaction->date->format($carbonFormat);
$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;

View File

@ -96,10 +96,11 @@ interface BudgetRepositoryInterface
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
* @param bool $noBudget
*
* @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
@ -119,7 +120,7 @@ interface BudgetRepositoryInterface
*
* @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
@ -143,7 +144,7 @@ interface BudgetRepositoryInterface
*
* @return Budget
*/
public function update(Budget $budget, array $data) : Budget;
public function update(Budget $budget, array $data): Budget;
/**
* @param Budget $budget
@ -154,6 +155,6 @@ interface BudgetRepositoryInterface
*
* @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 DB;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Models\Category;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\User;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Collection;
use Navigation;
/**
* Class CategoryRepository
@ -172,6 +175,32 @@ class CategoryRepository implements CategoryRepositoryInterface
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 Collection $accounts
@ -233,6 +262,7 @@ class CategoryRepository implements CategoryRepositoryInterface
{
$sum = $this->sumInPeriod($categories, $accounts, TransactionType::WITHDRAWAL, $start, $end);
$sum = bcmul($sum, '-1');
return $sum;
}
@ -284,6 +314,55 @@ class CategoryRepository implements CategoryRepositoryInterface
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 $accounts
@ -404,5 +483,4 @@ class CategoryRepository implements CategoryRepositoryInterface
return $sum;
}
}

View File

@ -49,7 +49,7 @@ interface CategoryRepositoryInterface
*
* @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
@ -58,7 +58,7 @@ interface CategoryRepositoryInterface
*
* @return Category
*/
public function find(int $categoryId) : Category;
public function find(int $categoryId): Category;
/**
* Find a category
@ -67,7 +67,7 @@ interface CategoryRepositoryInterface
*
* @return Category
*/
public function findByName(string $name) : Category;
public function findByName(string $name): Category;
/**
* @param Category $category
@ -83,6 +83,20 @@ interface CategoryRepositoryInterface
*/
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.
*
@ -110,7 +124,7 @@ interface CategoryRepositoryInterface
*
* @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

View File

@ -18,7 +18,7 @@
</thead>
<tbody>
{% for category in categories %}
{% if income[category.id] %}
{% if report.income[category.id] or report.expense[category.id] %}
<tr>
<td data-value="{{ category.name }}">
<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 %}
{# income first #}
{% if(income[category.id].entries[key]) %}
<td data-value="{{ income[category.id].entries[key] }}">
{{ income[category.id].entries[key]|formatAmount }}
{% if(report.income[category.id].entries[key]) %}
<td data-value="{{ report.income[category.id].entries[key] }}">
{{ report.income[category.id].entries[key]|formatAmount }}
</td>
{% else %}
<td data-value="0">
{{ 0|formatAmount }}
</td>
{% endif %}
{# expenses #}
<td data-value="0">
<!-- expense -->
</td>
{% if(report.expense[category.id].entries[key]) %}
<td data-value="{{ report.expense[category.id].entries[key] }}">
{{ report.expense[category.id].entries[key]|formatAmount }}
</td>
{% else %}
<td data-value="0">
</td>
{% endif %}
{% endfor %}
<td data-value="{{ info.sum }}">
0
<td data-value="{{ report.income[category.id].sum }}">
{{ report.income[category.id].sum }}
</td>
<td data-value="{{ info.sum }}">
1
<td data-value="{{ report.expense[category.id].sum }}">
{{ report.expense[category.id].sum }}
</td>
</tr>
{% endif %}