diff --git a/tailbone/templates/master/index.mako b/tailbone/templates/master/index.mako
index d2215abe..b0ee17d6 100644
--- a/tailbone/templates/master/index.mako
+++ b/tailbone/templates/master/index.mako
@@ -28,6 +28,19 @@
<%def name="grid_tools()">
+ ## grid totals
+ % if master.supports_grid_totals:
+
+ {{ gridTotalsFetching ? "Working, please wait..." : "Show Totals" }}
+
+
+ Totals: {{ gridTotalsDisplay }}
+
+ % endif
+
## download search results
% if master.results_downloadable and master.has_perm('download_results'):
+ % if master.supports_grid_totals:
+ ${grid.component_studly}Data.gridTotalsDisplay = null
+ ${grid.component_studly}Data.gridTotalsFetching = false
+
+ ${grid.component_studly}.methods.gridTotalsFetch = function() {
+ this.gridTotalsFetching = true
+
+ let url = '${url(f'{route_prefix}.fetch_grid_totals')}'
+ this.simpleGET(url, {}, response => {
+ this.gridTotalsDisplay = response.data.totals_display
+ this.gridTotalsFetching = false
+ }, response => {
+ this.gridTotalsFetching = false
+ })
+ }
+
+ ${grid.component_studly}.methods.appliedFiltersHook = function() {
+ this.gridTotalsDisplay = null
+ this.gridTotalsFetching = false
+ }
+ % endif
+
## maybe auto-redirect to download latest results file
% if download_results_path:
ThisPage.methods.downloadResultsRedirect = function() {
diff --git a/tailbone/views/master.py b/tailbone/views/master.py
index c515da7b..04262124 100644
--- a/tailbone/views/master.py
+++ b/tailbone/views/master.py
@@ -107,6 +107,7 @@ class MasterView(View):
set_deletable = False
supports_autocomplete = False
supports_set_enabled_toggle = False
+ supports_grid_totals = False
populatable = False
mergeable = False
merge_handler = None
@@ -1837,6 +1838,9 @@ class MasterView(View):
self.request.session.flash("Deleted {} {}".format(len(objects), model_title_plural))
return self.redirect(self.get_index_url())
+ def fetch_grid_totals(self):
+ return {'totals_display': "TODO: totals go here"}
+
def oneoff_import(self, importer, host_object=None):
"""
Basic helper method, to do a one-off import (or export, depending on
@@ -5198,6 +5202,15 @@ class MasterView(View):
config.add_view(cls, attr='download_results_rows', route_name='{}.download_results_rows'.format(route_prefix),
permission='{}.download_results_rows'.format(permission_prefix))
+ # fetch total hours
+ if cls.supports_grid_totals:
+ config.add_route(f'{route_prefix}.fetch_grid_totals',
+ f'{url_prefix}/fetch-grid-totals')
+ config.add_view(cls, attr='fetch_grid_totals',
+ route_name=f'{route_prefix}.fetch_grid_totals',
+ permission=f'{permission_prefix}.list',
+ renderer='json')
+
# configure
if cls.configurable:
config.add_tailbone_permission(permission_prefix,
diff --git a/tailbone/views/members.py b/tailbone/views/members.py
index d2a0e455..61b190c2 100644
--- a/tailbone/views/members.py
+++ b/tailbone/views/members.py
@@ -406,6 +406,7 @@ class MemberEquityPaymentView(MasterView):
model_class = model.MemberEquityPayment
route_prefix = 'member_equity_payments'
url_prefix = '/member-equity-payments'
+ supports_grid_totals = True
has_versions = True
grid_columns = [
@@ -470,6 +471,12 @@ class MemberEquityPaymentView(MasterView):
key = getattr(payment.member, field)
return key
+ def fetch_grid_totals(self):
+ app = self.get_rattail_app()
+ results = self.get_effective_data()
+ total = sum([payment.amount for payment in results])
+ return {'totals_display': app.render_currency(total)}
+
def configure_form(self, f):
super().configure_form(f)
model = self.model