mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
A better tag overview as preparation for #525
This commit is contained in:
parent
78b71e72f1
commit
373b9cdd9f
@ -13,13 +13,17 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace FireflyIII\Http\Controllers;
|
namespace FireflyIII\Http\Controllers;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Exception;
|
||||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||||
use FireflyIII\Http\Requests\TagFormRequest;
|
use FireflyIII\Http\Requests\TagFormRequest;
|
||||||
use FireflyIII\Models\Tag;
|
use FireflyIII\Models\Tag;
|
||||||
use FireflyIII\Models\Transaction;
|
use FireflyIII\Models\Transaction;
|
||||||
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
|
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
|
||||||
|
use FireflyIII\Support\CacheProperties;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Navigation;
|
||||||
use Preferences;
|
use Preferences;
|
||||||
use Session;
|
use Session;
|
||||||
use URL;
|
use URL;
|
||||||
@ -41,8 +45,12 @@ use View;
|
|||||||
class TagController extends Controller
|
class TagController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
public $tagOptions = [];
|
public $tagOptions = [];
|
||||||
|
|
||||||
|
/** @var TagRepositoryInterface */
|
||||||
|
protected $repository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -53,15 +61,19 @@ class TagController extends Controller
|
|||||||
|
|
||||||
$this->middleware(
|
$this->middleware(
|
||||||
function ($request, $next) {
|
function ($request, $next) {
|
||||||
View::share('title', 'Tags');
|
$this->repository = app(TagRepositoryInterface::class);
|
||||||
View::share('mainTitleIcon', 'fa-tags');
|
|
||||||
$this->tagOptions = [
|
$this->tagOptions = [
|
||||||
'nothing' => trans('firefly.regular_tag'),
|
'nothing' => trans('firefly.regular_tag'),
|
||||||
'balancingAct' => trans('firefly.balancing_act'),
|
'balancingAct' => trans('firefly.balancing_act'),
|
||||||
'advancePayment' => trans('firefly.advance_payment'),
|
'advancePayment' => trans('firefly.advance_payment'),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
View::share('title', strval(trans('firefly.tags')));
|
||||||
|
View::share('mainTitleIcon', 'fa-tags');
|
||||||
View::share('tagOptions', $this->tagOptions);
|
View::share('tagOptions', $this->tagOptions);
|
||||||
|
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -113,16 +125,15 @@ class TagController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param TagRepositoryInterface $repository
|
* @param Tag $tag
|
||||||
* @param Tag $tag
|
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function destroy(TagRepositoryInterface $repository, Tag $tag)
|
public function destroy(Tag $tag)
|
||||||
{
|
{
|
||||||
|
|
||||||
$tagName = $tag->tag;
|
$tagName = $tag->tag;
|
||||||
$repository->destroy($tag);
|
$this->repository->destroy($tag);
|
||||||
|
|
||||||
Session::flash('success', strval(trans('firefly.deleted_tag', ['tag' => e($tagName)])));
|
Session::flash('success', strval(trans('firefly.deleted_tag', ['tag' => e($tagName)])));
|
||||||
Preferences::mark();
|
Preferences::mark();
|
||||||
@ -216,15 +227,34 @@ class TagController extends Controller
|
|||||||
*
|
*
|
||||||
* @return View
|
* @return View
|
||||||
*/
|
*/
|
||||||
public function show(Request $request, JournalCollectorInterface $collector, Tag $tag)
|
public function show(Request $request, JournalCollectorInterface $collector, Tag $tag, string $moment = '')
|
||||||
{
|
{
|
||||||
|
$range = Preferences::get('viewRange', '1M')->data;
|
||||||
|
|
||||||
|
if (strlen($moment) > 0) {
|
||||||
|
try {
|
||||||
|
$start = new Carbon($moment);
|
||||||
|
$end = Navigation::endOfPeriod($start, $range);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$start = Navigation::startOfPeriod($this->repository->firstUseDate($tag), $range);
|
||||||
|
$end = Navigation::startOfPeriod($this->repository->lastUseDate($tag), $range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (strlen($moment) === 0) {
|
||||||
|
$start = clone session('start', Carbon::now()->startOfMonth());
|
||||||
|
$end = clone session('end', Carbon::now()->endOfMonth());
|
||||||
|
}
|
||||||
|
|
||||||
$subTitle = $tag->tag;
|
$subTitle = $tag->tag;
|
||||||
$subTitleIcon = 'fa-tag';
|
$subTitleIcon = 'fa-tag';
|
||||||
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
|
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
|
||||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||||
|
$periods = $this->getPeriodOverview($tag);
|
||||||
|
|
||||||
// use collector:
|
// use collector:
|
||||||
$collector->setAllAssetAccounts()->setLimit($pageSize)->setPage($page)->setTag($tag)->withBudgetInformation()->withCategoryInformation();
|
$collector->setAllAssetAccounts()
|
||||||
|
->setLimit($pageSize)->setPage($page)->setTag($tag)
|
||||||
|
->withBudgetInformation()->withCategoryInformation()->setRange($start, $end);
|
||||||
$journals = $collector->getPaginatedJournals();
|
$journals = $collector->getPaginatedJournals();
|
||||||
$journals->setPath('tags/show/' . $tag->id);
|
$journals->setPath('tags/show/' . $tag->id);
|
||||||
|
|
||||||
@ -234,20 +264,18 @@ class TagController extends Controller
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return view('tags.show', compact('tag', 'subTitle', 'subTitleIcon', 'journals', 'sum'));
|
return view('tags.show', compact('tag', 'periods', 'subTitle', 'subTitleIcon', 'journals', 'sum', 'start', 'end'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param TagFormRequest $request
|
* @param TagFormRequest $request
|
||||||
*
|
|
||||||
* @param TagRepositoryInterface $repository
|
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function store(TagFormRequest $request, TagRepositoryInterface $repository)
|
public function store(TagFormRequest $request)
|
||||||
{
|
{
|
||||||
$data = $request->collectTagData();
|
$data = $request->collectTagData();
|
||||||
$repository->store($data);
|
$this->repository->store($data);
|
||||||
|
|
||||||
Session::flash('success', strval(trans('firefly.created_tag', ['tag' => e($data['tag'])])));
|
Session::flash('success', strval(trans('firefly.created_tag', ['tag' => e($data['tag'])])));
|
||||||
Preferences::mark();
|
Preferences::mark();
|
||||||
@ -265,16 +293,15 @@ class TagController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param TagFormRequest $request
|
* @param TagFormRequest $request
|
||||||
* @param TagRepositoryInterface $repository
|
* @param Tag $tag
|
||||||
* @param Tag $tag
|
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function update(TagFormRequest $request, TagRepositoryInterface $repository, Tag $tag)
|
public function update(TagFormRequest $request, Tag $tag)
|
||||||
{
|
{
|
||||||
$data = $request->collectTagData();
|
$data = $request->collectTagData();
|
||||||
$repository->update($tag, $data);
|
$this->repository->update($tag, $data);
|
||||||
|
|
||||||
Session::flash('success', strval(trans('firefly.updated_tag', ['tag' => e($data['tag'])])));
|
Session::flash('success', strval(trans('firefly.updated_tag', ['tag' => e($data['tag'])])));
|
||||||
Preferences::mark();
|
Preferences::mark();
|
||||||
@ -289,4 +316,50 @@ class TagController extends Controller
|
|||||||
// redirect to previous URL.
|
// redirect to previous URL.
|
||||||
return redirect(session('tags.edit.url'));
|
return redirect(session('tags.edit.url'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Tag $tag
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
private function getPeriodOverview(Tag $tag): Collection
|
||||||
|
{
|
||||||
|
// get first and last tag date from tag:
|
||||||
|
$range = Preferences::get('viewRange', '1M')->data;
|
||||||
|
$start = Navigation::startOfPeriod($this->repository->firstUseDate($tag), $range);
|
||||||
|
$end = Navigation::startOfPeriod($this->repository->lastUseDate($tag), $range);
|
||||||
|
// properties for entries with their amounts.
|
||||||
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty('tag.entries');
|
||||||
|
$cache->addProperty($tag->id);
|
||||||
|
|
||||||
|
if ($cache->has()) {
|
||||||
|
return $cache->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
$collection = new Collection;
|
||||||
|
|
||||||
|
// while end larger or equal to start
|
||||||
|
while ($end >= $start) {
|
||||||
|
$currentEnd = Navigation::endOfPeriod($end, $range);
|
||||||
|
|
||||||
|
// get expenses and what-not in this period and this tag.
|
||||||
|
$arr = [
|
||||||
|
'date_string' => $end->format('Y-m-d'),
|
||||||
|
'date_name' => Navigation::periodShow($end, $range),
|
||||||
|
'date' => $end,
|
||||||
|
'spent' => $this->repository->spentInperiod($tag, $end, $currentEnd),
|
||||||
|
'earned' => $this->repository->earnedInperiod($tag, $end, $currentEnd),
|
||||||
|
];
|
||||||
|
$collection->push($arr);
|
||||||
|
|
||||||
|
$end = Navigation::subtractPeriod($end, $range, 1);
|
||||||
|
}
|
||||||
|
$cache->store($collection);
|
||||||
|
|
||||||
|
return $collection;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@ declare(strict_types = 1);
|
|||||||
namespace FireflyIII\Repositories\Tag;
|
namespace FireflyIII\Repositories\Tag;
|
||||||
|
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||||
use FireflyIII\Models\Tag;
|
use FireflyIII\Models\Tag;
|
||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
use FireflyIII\Models\TransactionType;
|
use FireflyIII\Models\TransactionType;
|
||||||
@ -121,6 +123,21 @@ class TagRepository implements TagRepositoryInterface
|
|||||||
return new Tag;
|
return new Tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Tag $tag
|
||||||
|
*
|
||||||
|
* @return Carbon
|
||||||
|
*/
|
||||||
|
public function firstUseDate(Tag $tag): Carbon
|
||||||
|
{
|
||||||
|
$journal = $tag->transactionJournals()->orderBy('date', 'ASC')->first();
|
||||||
|
if (!is_null($journal)) {
|
||||||
|
return $journal->date;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Carbon;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
@ -137,6 +154,21 @@ class TagRepository implements TagRepositoryInterface
|
|||||||
return $tags;
|
return $tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Tag $tag
|
||||||
|
*
|
||||||
|
* @return Carbon
|
||||||
|
*/
|
||||||
|
public function lastUseDate(Tag $tag): Carbon
|
||||||
|
{
|
||||||
|
$journal = $tag->transactionJournals()->orderBy('date', 'DESC')->first();
|
||||||
|
if (!is_null($journal)) {
|
||||||
|
return $journal->date;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Carbon;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $data
|
* @param array $data
|
||||||
*
|
*
|
||||||
@ -353,4 +385,40 @@ class TagRepository implements TagRepositoryInterface
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Tag $tag
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function earnedInPeriod(Tag $tag, Carbon $start, Carbon $end): string
|
||||||
|
{
|
||||||
|
/** @var JournalCollectorInterface $collector */
|
||||||
|
$collector = app(JournalCollectorInterface::class, [$this->user]);
|
||||||
|
$collector->setRange($start, $end)->setTypes([TransactionType::DEPOSIT])->setAllAssetAccounts()->setTag($tag);
|
||||||
|
$set = $collector->getJournals();
|
||||||
|
$sum = strval($set->sum('transaction_amount'));
|
||||||
|
|
||||||
|
return $sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Tag $tag
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function spentInPeriod(Tag $tag, Carbon $start, Carbon $end): string
|
||||||
|
{
|
||||||
|
/** @var JournalCollectorInterface $collector */
|
||||||
|
$collector = app(JournalCollectorInterface::class, [$this->user]);
|
||||||
|
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setAllAssetAccounts()->setTag($tag);
|
||||||
|
$set = $collector->getJournals();
|
||||||
|
$sum = strval($set->sum('transaction_amount'));
|
||||||
|
|
||||||
|
return $sum;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace FireflyIII\Repositories\Tag;
|
namespace FireflyIII\Repositories\Tag;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Models\Tag;
|
use FireflyIII\Models\Tag;
|
||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@ -44,6 +45,15 @@ interface TagRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function destroy(Tag $tag): bool;
|
public function destroy(Tag $tag): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Tag $tag
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function earnedInPeriod(Tag $tag, Carbon $start, Carbon $end): string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $tagId
|
* @param int $tagId
|
||||||
*
|
*
|
||||||
@ -58,6 +68,13 @@ interface TagRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function findByTag(string $tag): Tag;
|
public function findByTag(string $tag): Tag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Tag $tag
|
||||||
|
*
|
||||||
|
* @return Carbon
|
||||||
|
*/
|
||||||
|
public function firstUseDate(Tag $tag): Carbon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns all the user's tags.
|
* This method returns all the user's tags.
|
||||||
*
|
*
|
||||||
@ -65,6 +82,22 @@ interface TagRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function get(): Collection;
|
public function get(): Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Tag $tag
|
||||||
|
*
|
||||||
|
* @return Carbon
|
||||||
|
*/
|
||||||
|
public function lastUseDate(Tag $tag): Carbon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Tag $tag
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function spentInPeriod(Tag $tag, Carbon $start, Carbon $end): string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method stores a tag.
|
* This method stores a tag.
|
||||||
*
|
*
|
||||||
|
@ -76,7 +76,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-612 col-md-12 col-sm-12 col-xs-12">
|
<div class="col-lg-offset-10 col-lg-2 col-md-offset-10 col-md-2 col-sm-12 col-xs-12">
|
||||||
|
<p class="small text-center"><a href="{{ route('tags.show',[tag.id,'all']) }}">{{ 'showEverything'|_ }}</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-10 col-md-10 col-sm-12 col-xs-12">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header with-border">
|
<div class="box-header with-border">
|
||||||
<h3 class="box-title">{{ 'transactions'|_ }}</h3>
|
<h3 class="box-title">{{ 'transactions'|_ }}</h3>
|
||||||
@ -99,11 +104,42 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-lg-2 col-md-2 col-sm-12 col-xs-12">
|
||||||
|
{% for period in periods %}
|
||||||
|
{% if period.spent != 0 or period.earned != 0 %}
|
||||||
|
<div class="box {% if period.date == start %}box-solid box-primary{% endif %}">
|
||||||
|
<div class="box-header with-border">
|
||||||
|
<h3 class="box-title"><a href="{{ route('tags.show',[tag.id, period.date_string]) }}">{{ period.date_name }}</a>
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div class="box-body no-padding">
|
||||||
|
<table class="table table-hover">
|
||||||
|
{% if period.spent != 0 %}
|
||||||
|
<tr>
|
||||||
|
<td style="width:33%;">{{ 'spent'|_ }}</td>
|
||||||
|
<td style="text-align: right;">{{ period.spent|formatAmount }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
{% if period.earned != 0 %}
|
||||||
|
<tr>
|
||||||
|
<td style="width:33%;">{{ 'earned'|_ }}</td>
|
||||||
|
<td style="text-align: right;">{{ period.earned|formatAmount }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-offset-10 col-lg-2 col-md-offset-10 col-md-2 col-sm-12 col-xs-12">
|
||||||
|
<p class="small text-center"><a href="{{ route('tags.show',[tag.id,'all']) }}">{{ 'showEverything'|_ }}</a></p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script type="text/javascript">
|
|
||||||
var tagID = {{ tag.id }};
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -586,7 +586,9 @@ Route::group(
|
|||||||
|
|
||||||
Route::get('', ['uses' => 'TagController@index', 'as' => 'index']);
|
Route::get('', ['uses' => 'TagController@index', 'as' => 'index']);
|
||||||
Route::get('create', ['uses' => 'TagController@create', 'as' => 'create']);
|
Route::get('create', ['uses' => 'TagController@create', 'as' => 'create']);
|
||||||
Route::get('show/{tag}', ['uses' => 'TagController@show', 'as' => 'show']);
|
|
||||||
|
Route::get('show/{tag}/{date?}', ['uses' => 'TagController@show', 'as' => 'show']);
|
||||||
|
|
||||||
Route::get('edit/{tag}', ['uses' => 'TagController@edit', 'as' => 'edit']);
|
Route::get('edit/{tag}', ['uses' => 'TagController@edit', 'as' => 'edit']);
|
||||||
Route::get('delete/{tag}', ['uses' => 'TagController@delete', 'as' => 'delete']);
|
Route::get('delete/{tag}', ['uses' => 'TagController@delete', 'as' => 'delete']);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user