Graph previous year totals and year-to-date totals next to budget listing/filtering results
This commit is contained in:
parent
8d3a7b7ed0
commit
603e276bac
@ -111,6 +111,11 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% if yearly_totals %}
|
||||||
|
<h2>Yearly totals</h2>
|
||||||
|
<canvas id="chartYearlyTotals"></canvas>
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block head %}
|
{% block head %}
|
||||||
@ -123,4 +128,41 @@
|
|||||||
<script>
|
<script>
|
||||||
$('.ui.dropdown').dropdown();
|
$('.ui.dropdown').dropdown();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
{% if yearly_totals %}
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.3.0/dist/chart.umd.js" integrity="sha256-5dsP1lVzcWPn5aOwu+zs+G+TqAu9oT8NUNM0C4n3H+4=" crossorigin="anonymous"></script>
|
||||||
|
<script>
|
||||||
|
const yearlyTotalsData = JSON.parse({{ import('json').dumps(import('json').dumps(yearly_totals))|safe }});
|
||||||
|
|
||||||
|
new Chart(document.getElementById('chartYearlyTotals'), {
|
||||||
|
type: 'bar',
|
||||||
|
data: {
|
||||||
|
labels: yearlyTotalsData.map(x => x[0]),
|
||||||
|
datasets: [{
|
||||||
|
label: {{ import('json').dumps(import('json').dumps(request.GET.get('cost_centre', 'all')))|safe }},
|
||||||
|
data: yearlyTotalsData.map(x => x[1]),
|
||||||
|
backgroundColor: yearlyTotalsData.map(x => x[1] >= 0 ? '#36a2eb' : '#ff6384')
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
indexAxis: 'y',
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
beginAtZero: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
display: false
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
callbacks: {
|
||||||
|
label: i => '$' + i.parsed.x.toFixed(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -36,6 +36,7 @@ from ssmain.email import Emailer
|
|||||||
|
|
||||||
import csv
|
import csv
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from decimal import Decimal
|
||||||
import functools
|
import functools
|
||||||
import io
|
import io
|
||||||
import itertools
|
import itertools
|
||||||
@ -266,13 +267,30 @@ def budget_list(request):
|
|||||||
if group is not None:
|
if group is not None:
|
||||||
group.append(revision)
|
group.append(revision)
|
||||||
|
|
||||||
|
# Get yearly totals
|
||||||
|
if request.GET.get('cost_centre', 'all') != 'all':
|
||||||
|
yearly_totals = [[y, float(t)] for y, t in get_yearly_totals(budgets_filtered)]
|
||||||
|
else:
|
||||||
|
yearly_totals = None
|
||||||
|
|
||||||
return render(request, 'sstreasury/budget_list.html', {
|
return render(request, 'sstreasury/budget_list.html', {
|
||||||
'budgets_action': budgets_action,
|
'budgets_action': budgets_action,
|
||||||
'budgets_open': budgets_open,
|
'budgets_open': budgets_open,
|
||||||
'budgets_closed': budgets_closed,
|
'budgets_closed': budgets_closed,
|
||||||
|
'yearly_totals': yearly_totals,
|
||||||
'page': page
|
'page': page
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def get_yearly_totals(budgets_filtered):
|
||||||
|
"""Get total net profit per calendar year"""
|
||||||
|
|
||||||
|
results = []
|
||||||
|
|
||||||
|
for year, g in itertools.groupby(sorted(budgets_filtered, key=lambda r: r.time.year), key=lambda r: r.time.year):
|
||||||
|
results.append((year, sum((r.get_revenue_total() - r.get_expense_total() for r in g), Decimal('0'))))
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@uses_budget
|
@uses_budget
|
||||||
def budget_view(request, budget, revision):
|
def budget_view(request, budget, revision):
|
||||||
|
Loading…
Reference in New Issue
Block a user