diff --git a/tailbone/menus.py b/tailbone/menus.py index 9a0ba066..8aebf043 100644 --- a/tailbone/menus.py +++ b/tailbone/menus.py @@ -332,6 +332,12 @@ class MenuHandler(GenericHandler): 'route': 'members', 'perm': 'members.list', }, + { + 'title': "Membership Types", + 'route': 'membership_types', + 'perm': 'membership_types.list', + }, + {'type': 'sep'}, { 'title': "Customers", 'route': 'customers', @@ -342,22 +348,23 @@ class MenuHandler(GenericHandler): 'route': 'customergroups', 'perm': 'customergroups.list', }, + { + 'title': "Pending Customers", + 'route': 'pending_customers', + 'perm': 'pending_customers.list', + }, + {'type': 'sep'}, { 'title': "Employees", 'route': 'employees', 'perm': 'employees.list', }, + {'type': 'sep'}, { 'title': "All People", 'route': 'people', 'perm': 'people.list', }, - {'type': 'sep'}, - { - 'title': "Pending Customers", - 'route': 'pending_customers', - 'perm': 'pending_customers.list', - }, ], } diff --git a/tailbone/templates/people/view_profile_buefy.mako b/tailbone/templates/people/view_profile_buefy.mako index 075735cc..f21c021e 100644 --- a/tailbone/templates/people/view_profile_buefy.mako +++ b/tailbone/templates/people/view_profile_buefy.mako @@ -551,6 +551,16 @@ {{ member._key }} + + + {{ member.membership_type_name }} + + + {{ member.membership_type_name }} + + + {{ member.active }} diff --git a/tailbone/views/members.py b/tailbone/views/members.py index 955a217f..9f96e667 100644 --- a/tailbone/views/members.py +++ b/tailbone/views/members.py @@ -27,13 +27,70 @@ Member Views import sqlalchemy as sa from rattail.db import model +from rattail.db.model import MembershipType, Member from deform import widget as dfwidget +from webhelpers2.html import tags from tailbone import grids from tailbone.views import MasterView +class MembershipTypeView(MasterView): + """ + Master view for Membership Types + """ + model_class = MembershipType + route_prefix = 'membership_types' + url_prefix = '/membership-types' + has_versions = True + + labels = { + 'id': "ID", + } + + grid_columns = [ + 'number', + 'name', + ] + + has_rows = True + model_row_class = Member + rows_title = "Members" + + row_grid_columns = [ + '_member_key_', + 'person', + 'active', + 'equity_current', + 'equity_total', + 'joined', + 'withdrew', + ] + + def configure_grid(self, g): + super().configure_grid(g) + + g.set_sort_defaults('number') + + g.set_link('number') + g.set_link('name') + + def get_row_data(self, memtype): + model = self.model + return self.Session.query(model.Member)\ + .filter(model.Member.membership_type == memtype) + + def get_parent(self, member): + return member.membership_type + + def configure_row_grid(self, g): + super().configure_row_grid(g) + + g.filters['active'].default_active = True + g.filters['active'].default_verb = 'is_true' + + class MemberView(MasterView): """ Master view for the Member class. @@ -51,9 +108,7 @@ class MemberView(MasterView): grid_columns = [ '_member_key_', 'person', - 'customer', - 'email', - 'phone', + 'membership_type', 'active', 'equity_current', 'joined', @@ -66,6 +121,7 @@ class MemberView(MasterView): 'customer', 'default_email', 'default_phone', + 'membership_type', 'active', 'equity_current', 'equity_payment_due', @@ -75,6 +131,7 @@ class MemberView(MasterView): def configure_grid(self, g): super(MemberView, self).configure_grid(g) + model = self.model # member key field = self.get_member_key_field() @@ -111,6 +168,12 @@ class MemberView(MasterView): g.set_filter('email', model.MemberEmailAddress.address) g.set_label('email', "Email Address") + # membership_type + g.set_joiner('membership_type', lambda q: q.outerjoin(model.MembershipType)) + g.set_sorter('membership_type', model.MembershipType.name) + g.set_filter('membership_type', model.MembershipType.name, + label="Membership Type Name") + g.set_link('person') g.set_link('customer') @@ -174,6 +237,9 @@ class MemberView(MasterView): if not self.creating and member.phones: f.set_default('default_phone', member.phones[0].number) + # membership_type + f.set_renderer('membership_type', self.render_membership_type) + if self.creating: f.remove_fields( 'equity_total', @@ -190,6 +256,14 @@ class MemberView(MasterView): if member.phones: return member.phones[0].number + def render_membership_type(self, member, field): + memtype = getattr(member, field) + if not memtype: + return + text = str(memtype) + url = self.request.route_url('membership_types.view', uuid=memtype.uuid) + return tags.link_to(text, url) + def configure_get_simple_settings(self): return [ @@ -204,6 +278,9 @@ class MemberView(MasterView): def defaults(config, **kwargs): base = globals() + MembershipTypeView = kwargs.get('MembershipTypeView', base['MembershipTypeView']) + MembershipTypeView.defaults(config) + MemberView = kwargs.get('MemberView', base['MemberView']) MemberView.defaults(config) diff --git a/tailbone/views/people.py b/tailbone/views/people.py index dc75b8aa..89b857f1 100644 --- a/tailbone/views/people.py +++ b/tailbone/views/people.py @@ -585,7 +585,7 @@ class PersonView(MasterView): uuid=member.person_uuid) key = self.get_member_key_field() - return { + data = { 'uuid': member.uuid, '_key': getattr(member, key), 'number': member.number, @@ -602,6 +602,18 @@ class PersonView(MasterView): 'view_profile_url': profile_url, } + membership_type = member.membership_type + if membership_type: + data.update({ + 'membership_type_uuid': membership_type.uuid, + 'membership_type_number': membership_type.number, + 'membership_type_name': membership_type.name, + 'view_membership_type_url': self.request.route_url( + 'membership_types.view', uuid=membership_type.uuid), + }) + + return data + def get_context_employee(self, employee): """ Return a dict of context data for the given employee.