From 96e5c4279539229f8d400a90a6c4e31160d4807c Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Wed, 24 Jan 2018 23:53:12 -0600 Subject: [PATCH] Add support for detaching Person from Customer --- tailbone/templates/customers/view.mako | 21 +++++ tailbone/views/customers.py | 106 +++++++++++++++++++++++-- 2 files changed, 121 insertions(+), 6 deletions(-) create mode 100644 tailbone/templates/customers/view.mako diff --git a/tailbone/templates/customers/view.mako b/tailbone/templates/customers/view.mako new file mode 100644 index 00000000..27cc619c --- /dev/null +++ b/tailbone/templates/customers/view.mako @@ -0,0 +1,21 @@ +## -*- coding: utf-8; -*- +<%inherit file="/master/view.mako" /> + +<%def name="extra_javascript()"> + ${parent.extra_javascript()} + % if master.people_detachable and request.has_perm('{}.detach_person'.format(permission_prefix)): + + % endif + + +${parent.body()} diff --git a/tailbone/views/customers.py b/tailbone/views/customers.py index 8135c52c..012a151f 100644 --- a/tailbone/views/customers.py +++ b/tailbone/views/customers.py @@ -37,6 +37,7 @@ from deform import widget as dfwidget from pyramid.httpexceptions import HTTPNotFound from webhelpers2.html import HTML, tags +from tailbone import grids from tailbone.db import Session from tailbone.views import MasterView3 as MasterView, AutocompleteView @@ -50,6 +51,7 @@ class CustomersView(MasterView): model_class = model.Customer has_versions = True supports_mobile = True + people_detachable = True labels = { 'id': "ID", @@ -78,6 +80,7 @@ class CustomersView(MasterView): 'active_in_pos', 'active_in_pos_sticky', 'people', + 'groups', ] def configure_grid(self, g): @@ -151,6 +154,11 @@ class CustomersView(MasterView): def configure_form(self, f): super(CustomersView, self).configure_form(f) customer = f.model_instance + permission_prefix = self.get_permission_prefix() + + # id + if not self.creating: + f.set_readonly('id') f.set_renderer('default_email', self.render_default_email) if not self.creating and customer.emails: @@ -160,21 +168,33 @@ class CustomersView(MasterView): if not self.creating and customer.phones: f.set_default('default_phone', customer.phones[0].number) - f.set_renderer('default_address', self.render_default_address) - f.set_readonly('default_address') + # default_address + if self.creating: + f.remove_field('default_address') + else: + f.set_renderer('default_address', self.render_default_address) + f.set_readonly('default_address') f.set_enum('email_preference', self.enum.EMAIL_PREFERENCE) preferences = list(self.enum.EMAIL_PREFERENCE.items()) preferences.insert(0, ('', "(no preference)")) f.set_widget('email_preference', dfwidget.SelectWidget(values=preferences)) - f.set_renderer('people', self.render_people) - f.set_readonly('people') - + # people if self.creating: f.remove_field('people') + elif self.viewing and self.request.has_perm('{}.detach_person'.format(permission_prefix)): + f.set_renderer('people', self.render_people_removable) else: - f.set_readonly('id') + f.set_renderer('people', self.render_people) + f.set_readonly('people') + + # groups + if self.creating: + f.remove_field('groups') + else: + f.set_renderer('groups', self.render_groups) + f.set_readonly('groups') # TODO: something like this should be supported for default_email, default_phone # def after_edit(self, customer): @@ -226,6 +246,46 @@ class CustomersView(MasterView): items.append(HTML.tag('li', link)) return HTML.tag('ul', HTML.literal('').join(items)) + def render_people_removable(self, customer, field): + people = customer.people + if not people: + return "" + + route_prefix = self.get_route_prefix() + permission_prefix = self.get_permission_prefix() + + view_url = lambda p, i: self.request.route_url('people.view', uuid=p.uuid) + actions = [ + grids.GridAction('view', icon='zoomin', url=view_url), + ] + if self.people_detachable and self.request.has_perm('{}.detach_person'.format(permission_prefix)): + url = lambda p, i: self.request.route_url('{}.detach_person'.format(route_prefix), + uuid=customer.uuid, person_uuid=p.uuid) + actions.append( + grids.GridAction('detach', icon='trash', url=url)) + + columns = ['first_name', 'last_name', 'display_name'] + g = grids.Grid( + key='{}.people'.format(route_prefix), + data=customer.people, + columns=columns, + labels={'display_name': "Full Name"}, + url=lambda p: self.request.route_url('people.view', uuid=p.uuid), + linked_columns=columns, + main_actions=actions) + return HTML.literal(g.render_grid()) + + def render_groups(self, customer, field): + groups = customer.groups + if not groups: + return "" + items = [] + for group in groups: + text = "({}) {}".format(group.id, group.name) + url = self.request.route_url('customergroups.view', uuid=group.uuid) + items.append(HTML.tag('li', tags.link_to(text, url))) + return HTML.tag('ul', HTML.literal('').join(items)) + # def configure_mobile_fieldset(self, fs): # fs.configure( # include=[ @@ -241,6 +301,40 @@ class CustomersView(MasterView): (model.CustomerPerson, 'customer_uuid'), ] + def detach_person(self): + customer = self.get_instance() + person = self.Session.query(model.Person).get(self.request.matchdict['person_uuid']) + if not person: + return self.notfound() + + if person in customer.people: + customer.people.remove(person) + else: + self.request.session.flash("No change; person \"{}\" not attached to customer \"{}\"".format( + person, customer)) + + return self.redirect(self.request.get_referrer()) + + @classmethod + def defaults(cls, config): + route_prefix = cls.get_route_prefix() + url_prefix = cls.get_url_prefix() + permission_prefix = cls.get_permission_prefix() + model_key = cls.get_model_key() + model_title = cls.get_model_title() + + cls._defaults(config) + + # detach person + if cls.people_detachable: + config.add_tailbone_permission(permission_prefix, '{}.detach_person'.format(permission_prefix), + "Detach a Person from a {}".format(model_title)) + config.add_route('{}.detach_person'.format(route_prefix), '{}/{{{}}}/detach-person/{{person_uuid}}'.format(url_prefix, model_key), + # request_method='POST', + ) + config.add_view(cls, attr='detach_person', route_name='{}.detach_person'.format(route_prefix), + permission='{}.detach_person'.format(permission_prefix)) + # # TODO: this is referenced by some custom apps, but should be moved?? # def unique_id(value, field):