Overhaul the "Personal" tab of profile view
should be much more useful now.. er, at least for those who track contact info on the Person record, but not those who track on the Customer record..
This commit is contained in:
parent
48864ab611
commit
6386b34516
File diff suppressed because it is too large
Load diff
|
@ -27,14 +27,16 @@ Person Views
|
||||||
from __future__ import unicode_literals, absolute_import
|
from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import logging
|
||||||
|
|
||||||
import six
|
import six
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from sqlalchemy import orm
|
from sqlalchemy import orm
|
||||||
|
|
||||||
from rattail.db import model, api
|
from rattail.db import model, api
|
||||||
|
from rattail.db.util import maxlen
|
||||||
from rattail.time import localtime
|
from rattail.time import localtime
|
||||||
from rattail.util import OrderedDict
|
from rattail.util import OrderedDict, simple_error
|
||||||
|
|
||||||
import colander
|
import colander
|
||||||
from pyramid.httpexceptions import HTTPFound, HTTPNotFound
|
from pyramid.httpexceptions import HTTPFound, HTTPNotFound
|
||||||
|
@ -44,6 +46,9 @@ from tailbone import forms, grids
|
||||||
from tailbone.views import MasterView
|
from tailbone.views import MasterView
|
||||||
|
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class PersonView(MasterView):
|
class PersonView(MasterView):
|
||||||
"""
|
"""
|
||||||
Master view for the Person class.
|
Master view for the Person class.
|
||||||
|
@ -430,6 +435,9 @@ class PersonView(MasterView):
|
||||||
'instance_title': self.get_instance_title(person),
|
'instance_title': self.get_instance_title(person),
|
||||||
'today': localtime(self.rattail_config).date(),
|
'today': localtime(self.rattail_config).date(),
|
||||||
'person_data': self.get_context_person(person),
|
'person_data': self.get_context_person(person),
|
||||||
|
'phone_type_options': self.get_phone_type_options(),
|
||||||
|
'email_type_options': self.get_email_type_options(),
|
||||||
|
'max_lengths': self.get_max_lengths(),
|
||||||
'customers_data': self.get_context_customers(person),
|
'customers_data': self.get_context_customers(person),
|
||||||
'members_data': self.get_context_members(person),
|
'members_data': self.get_context_members(person),
|
||||||
'employee': employee,
|
'employee': employee,
|
||||||
|
@ -442,17 +450,65 @@ class PersonView(MasterView):
|
||||||
template = 'view_profile_buefy' if use_buefy else 'view_profile'
|
template = 'view_profile_buefy' if use_buefy else 'view_profile'
|
||||||
return self.render_to_response(template, context)
|
return self.render_to_response(template, context)
|
||||||
|
|
||||||
def get_context_person(self, person):
|
def get_max_lengths(self):
|
||||||
|
model = self.model
|
||||||
return {
|
return {
|
||||||
|
'address_street': maxlen(model.PersonMailingAddress.street),
|
||||||
|
'address_street2': maxlen(model.PersonMailingAddress.street2),
|
||||||
|
'address_city': maxlen(model.PersonMailingAddress.city),
|
||||||
|
'address_state': maxlen(model.PersonMailingAddress.state),
|
||||||
|
'address_zipcode': maxlen(model.PersonMailingAddress.zipcode),
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_phone_type_options(self):
|
||||||
|
"""
|
||||||
|
Returns a list of "phone type" options, for use in dropdown.
|
||||||
|
"""
|
||||||
|
# TODO: should probably define this list somewhere else
|
||||||
|
phone_types = [
|
||||||
|
"Home",
|
||||||
|
"Mobile",
|
||||||
|
"Work",
|
||||||
|
"Other",
|
||||||
|
"Fax",
|
||||||
|
]
|
||||||
|
return [{'value': typ, 'label': typ}
|
||||||
|
for typ in phone_types]
|
||||||
|
|
||||||
|
def get_email_type_options(self):
|
||||||
|
"""
|
||||||
|
Returns a list of "email type" options, for use in dropdown.
|
||||||
|
"""
|
||||||
|
# TODO: should probably define this list somewhere else
|
||||||
|
email_types = [
|
||||||
|
"Home",
|
||||||
|
"Work",
|
||||||
|
"Other",
|
||||||
|
]
|
||||||
|
return [{'value': typ, 'label': typ}
|
||||||
|
for typ in email_types]
|
||||||
|
|
||||||
|
def get_context_person(self, person):
|
||||||
|
|
||||||
|
context = {
|
||||||
'uuid': person.uuid,
|
'uuid': person.uuid,
|
||||||
'first_name': person.first_name,
|
'first_name': person.first_name,
|
||||||
|
'middle_name': person.middle_name,
|
||||||
'last_name': person.last_name,
|
'last_name': person.last_name,
|
||||||
'display_name': person.display_name,
|
'display_name': person.display_name,
|
||||||
'view_url': self.get_action_url('view', person),
|
'view_url': self.get_action_url('view', person),
|
||||||
'view_profile_url': self.get_action_url('view_profile', person),
|
'view_profile_url': self.get_action_url('view_profile', person),
|
||||||
|
'phones': self.get_context_phones(person),
|
||||||
|
'emails': self.get_context_emails(person),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if person.address:
|
||||||
|
context['address'] = self.get_context_address(person.address)
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
def get_context_address(self, address):
|
def get_context_address(self, address):
|
||||||
|
person = address.person
|
||||||
return {
|
return {
|
||||||
'uuid': address.uuid,
|
'uuid': address.uuid,
|
||||||
'street': address.street,
|
'street': address.street,
|
||||||
|
@ -461,6 +517,7 @@ class PersonView(MasterView):
|
||||||
'state': address.state,
|
'state': address.state,
|
||||||
'zipcode': address.zipcode,
|
'zipcode': address.zipcode,
|
||||||
'display': six.text_type(address),
|
'display': six.text_type(address),
|
||||||
|
'invalid': self.handler.address_is_invalid(person, address),
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_context_customers(self, person):
|
def get_context_customers(self, person):
|
||||||
|
@ -547,6 +604,270 @@ class PersonView(MasterView):
|
||||||
customer = handler.ensure_customer(person)
|
customer = handler.ensure_customer(person)
|
||||||
return customer
|
return customer
|
||||||
|
|
||||||
|
def profile_edit_name(self):
|
||||||
|
"""
|
||||||
|
View which allows a person's name to be updated.
|
||||||
|
"""
|
||||||
|
person = self.get_instance()
|
||||||
|
data = dict(self.request.json_body)
|
||||||
|
|
||||||
|
self.handler.update_names(person,
|
||||||
|
first=data['first_name'],
|
||||||
|
middle=data['middle_name'],
|
||||||
|
last=data['last_name'])
|
||||||
|
|
||||||
|
self.Session.flush()
|
||||||
|
return {
|
||||||
|
'success': True,
|
||||||
|
'person': self.get_context_person(person),
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_context_phones(self, person):
|
||||||
|
data = []
|
||||||
|
for phone in person.phones:
|
||||||
|
data.append({
|
||||||
|
'uuid': phone.uuid,
|
||||||
|
'type': phone.type,
|
||||||
|
'number': phone.number,
|
||||||
|
'preferred': phone.preferred,
|
||||||
|
'preference': phone.preference,
|
||||||
|
})
|
||||||
|
return data
|
||||||
|
|
||||||
|
def profile_add_phone(self):
|
||||||
|
"""
|
||||||
|
View which adds a new phone number for the person.
|
||||||
|
"""
|
||||||
|
person = self.get_instance()
|
||||||
|
data = dict(self.request.json_body)
|
||||||
|
|
||||||
|
try:
|
||||||
|
phone = self.handler.add_phone(person, data['phone_number'],
|
||||||
|
type=data['phone_type'],
|
||||||
|
preferred=data['phone_preferred'])
|
||||||
|
except Exception as error:
|
||||||
|
log.warning("failed to add phone", exc_info=True)
|
||||||
|
return {'error': simple_error(error)}
|
||||||
|
|
||||||
|
self.Session.flush()
|
||||||
|
return {
|
||||||
|
'success': True,
|
||||||
|
'person': self.get_context_person(person),
|
||||||
|
}
|
||||||
|
|
||||||
|
def profile_update_phone(self):
|
||||||
|
"""
|
||||||
|
View which updates a phone number for the person.
|
||||||
|
"""
|
||||||
|
person = self.get_instance()
|
||||||
|
data = dict(self.request.json_body)
|
||||||
|
|
||||||
|
phone = self.Session.query(model.PersonPhoneNumber).get(data['phone_uuid'])
|
||||||
|
if not phone:
|
||||||
|
return {'error': "Phone not found."}
|
||||||
|
|
||||||
|
kwargs = {
|
||||||
|
'number': data['phone_number'],
|
||||||
|
'type': data['phone_type'],
|
||||||
|
}
|
||||||
|
if 'phone_preferred' in data:
|
||||||
|
kwargs['preferred'] = data['phone_preferred']
|
||||||
|
|
||||||
|
try:
|
||||||
|
phone = self.handler.update_phone(person, phone, **kwargs)
|
||||||
|
except Exception as error:
|
||||||
|
log.warning("failed to update phone", exc_info=True)
|
||||||
|
return {'error': simple_error(error)}
|
||||||
|
|
||||||
|
self.Session.flush()
|
||||||
|
return {
|
||||||
|
'success': True,
|
||||||
|
'person': self.get_context_person(person),
|
||||||
|
}
|
||||||
|
|
||||||
|
def profile_delete_phone(self):
|
||||||
|
"""
|
||||||
|
View which allows a person's phone number to be deleted.
|
||||||
|
"""
|
||||||
|
person = self.get_instance()
|
||||||
|
data = dict(self.request.json_body)
|
||||||
|
|
||||||
|
# validate phone
|
||||||
|
phone = self.Session.query(model.PersonPhoneNumber).get(data['phone_uuid'])
|
||||||
|
if not phone:
|
||||||
|
return {'error': "Phone not found."}
|
||||||
|
if phone not in person.phones:
|
||||||
|
return {'error': "Phone does not belong to this person."}
|
||||||
|
|
||||||
|
# remove phone
|
||||||
|
person.remove_phone(phone)
|
||||||
|
|
||||||
|
self.Session.flush()
|
||||||
|
return {
|
||||||
|
'success': True,
|
||||||
|
'person': self.get_context_person(person),
|
||||||
|
}
|
||||||
|
|
||||||
|
def profile_set_preferred_phone(self):
|
||||||
|
"""
|
||||||
|
View which allows a person's "preferred" phone to be set.
|
||||||
|
"""
|
||||||
|
person = self.get_instance()
|
||||||
|
data = dict(self.request.json_body)
|
||||||
|
|
||||||
|
# validate phone
|
||||||
|
phone = self.Session.query(model.PersonPhoneNumber).get(data['phone_uuid'])
|
||||||
|
if not phone:
|
||||||
|
return {'error': "Phone not found."}
|
||||||
|
if phone not in person.phones:
|
||||||
|
return {'error': "Phone does not belong to this person."}
|
||||||
|
|
||||||
|
# update phone preference
|
||||||
|
person.set_primary_phone(phone)
|
||||||
|
|
||||||
|
self.Session.flush()
|
||||||
|
return {
|
||||||
|
'success': True,
|
||||||
|
'person': self.get_context_person(person),
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_context_emails(self, person):
|
||||||
|
data = []
|
||||||
|
for email in person.emails:
|
||||||
|
data.append({
|
||||||
|
'uuid': email.uuid,
|
||||||
|
'type': email.type,
|
||||||
|
'address': email.address,
|
||||||
|
'invalid': email.invalid,
|
||||||
|
'preferred': email.preferred,
|
||||||
|
'preference': email.preference,
|
||||||
|
})
|
||||||
|
return data
|
||||||
|
|
||||||
|
def profile_add_email(self):
|
||||||
|
"""
|
||||||
|
View which adds a new email address for the person.
|
||||||
|
"""
|
||||||
|
person = self.get_instance()
|
||||||
|
data = dict(self.request.json_body)
|
||||||
|
|
||||||
|
kwargs = {
|
||||||
|
'type': data['email_type'],
|
||||||
|
'invalid': False,
|
||||||
|
}
|
||||||
|
if 'email_preferred' in data:
|
||||||
|
kwargs['preferred'] = data['email_preferred']
|
||||||
|
|
||||||
|
try:
|
||||||
|
email = self.handler.add_email(person, data['email_address'], **kwargs)
|
||||||
|
except Exception as error:
|
||||||
|
log.warning("failed to add email", exc_info=True)
|
||||||
|
return {'error': simple_error(error)}
|
||||||
|
|
||||||
|
self.Session.flush()
|
||||||
|
return {
|
||||||
|
'success': True,
|
||||||
|
'person': self.get_context_person(person),
|
||||||
|
}
|
||||||
|
|
||||||
|
def profile_update_email(self):
|
||||||
|
"""
|
||||||
|
View which updates an email address for the person.
|
||||||
|
"""
|
||||||
|
person = self.get_instance()
|
||||||
|
data = dict(self.request.json_body)
|
||||||
|
|
||||||
|
email = self.Session.query(model.PersonEmailAddress).get(data['email_uuid'])
|
||||||
|
if not email:
|
||||||
|
return {'error': "Email not found."}
|
||||||
|
|
||||||
|
try:
|
||||||
|
email = self.handler.update_email(person, email,
|
||||||
|
address=data['email_address'],
|
||||||
|
type=data['email_type'],
|
||||||
|
invalid=data['email_invalid'])
|
||||||
|
except Exception as error:
|
||||||
|
log.warning("failed to add email", exc_info=True)
|
||||||
|
return {'error': simple_error(error)}
|
||||||
|
|
||||||
|
self.Session.flush()
|
||||||
|
return {
|
||||||
|
'success': True,
|
||||||
|
'person': self.get_context_person(person),
|
||||||
|
}
|
||||||
|
|
||||||
|
def profile_delete_email(self):
|
||||||
|
"""
|
||||||
|
View which allows a person's email address to be deleted.
|
||||||
|
"""
|
||||||
|
person = self.get_instance()
|
||||||
|
data = dict(self.request.json_body)
|
||||||
|
|
||||||
|
# validate email
|
||||||
|
email = self.Session.query(model.PersonEmailAddress).get(data['email_uuid'])
|
||||||
|
if not email:
|
||||||
|
return {'error': "Email not found."}
|
||||||
|
if email not in person.emails:
|
||||||
|
return {'error': "Email does not belong to this person."}
|
||||||
|
|
||||||
|
# remove email
|
||||||
|
person.remove_email(email)
|
||||||
|
|
||||||
|
self.Session.flush()
|
||||||
|
|
||||||
|
return {
|
||||||
|
'success': True,
|
||||||
|
'person': self.get_context_person(person),
|
||||||
|
}
|
||||||
|
|
||||||
|
def profile_set_preferred_email(self):
|
||||||
|
"""
|
||||||
|
View which allows a person's "preferred" email to be set.
|
||||||
|
"""
|
||||||
|
person = self.get_instance()
|
||||||
|
data = dict(self.request.json_body)
|
||||||
|
|
||||||
|
# validate email
|
||||||
|
email = self.Session.query(model.PersonEmailAddress).get(data['email_uuid'])
|
||||||
|
if not email:
|
||||||
|
return {'error': "Email not found."}
|
||||||
|
if email not in person.emails:
|
||||||
|
return {'error': "Email does not belong to this person."}
|
||||||
|
|
||||||
|
# update email preference
|
||||||
|
person.set_primary_email(email)
|
||||||
|
|
||||||
|
self.Session.flush()
|
||||||
|
return {
|
||||||
|
'success': True,
|
||||||
|
'person': self.get_context_person(person),
|
||||||
|
}
|
||||||
|
|
||||||
|
def profile_edit_address(self):
|
||||||
|
"""
|
||||||
|
View which allows a person's mailing address to be updated.
|
||||||
|
"""
|
||||||
|
person = self.get_instance()
|
||||||
|
data = dict(self.request.json_body)
|
||||||
|
|
||||||
|
# update person address
|
||||||
|
address = person.address
|
||||||
|
if not address:
|
||||||
|
address = person.add_address()
|
||||||
|
address.street = data['street']
|
||||||
|
address.street2 = data['street2']
|
||||||
|
address.city = data['city']
|
||||||
|
address.state = data['state']
|
||||||
|
address.zipcode = data['zipcode']
|
||||||
|
|
||||||
|
self.handler.mark_address_invalid(person, address, data['invalid'])
|
||||||
|
|
||||||
|
self.Session.flush()
|
||||||
|
return {
|
||||||
|
'success': True,
|
||||||
|
'person': self.get_context_person(person),
|
||||||
|
}
|
||||||
|
|
||||||
def profile_start_employee(self):
|
def profile_start_employee(self):
|
||||||
"""
|
"""
|
||||||
View which will cause the person to start being an employee.
|
View which will cause the person to start being an employee.
|
||||||
|
@ -786,6 +1107,101 @@ class PersonView(MasterView):
|
||||||
config.add_view(cls, attr='view_profile', route_name='{}.view_profile'.format(route_prefix),
|
config.add_view(cls, attr='view_profile', route_name='{}.view_profile'.format(route_prefix),
|
||||||
permission='{}.view_profile'.format(permission_prefix))
|
permission='{}.view_profile'.format(permission_prefix))
|
||||||
|
|
||||||
|
# profile - edit personal details
|
||||||
|
config.add_tailbone_permission('people_profile',
|
||||||
|
'people_profile.edit_person',
|
||||||
|
"Edit the Personal details")
|
||||||
|
|
||||||
|
# profile - edit name
|
||||||
|
config.add_route('{}.profile_edit_name'.format(route_prefix),
|
||||||
|
'{}/profile/edit-name'.format(instance_url_prefix),
|
||||||
|
request_method='POST')
|
||||||
|
config.add_view(cls, attr='profile_edit_name',
|
||||||
|
route_name='{}.profile_edit_name'.format(route_prefix),
|
||||||
|
renderer='json',
|
||||||
|
permission='people_profile.edit_person')
|
||||||
|
|
||||||
|
# profile - add phone
|
||||||
|
config.add_route('{}.profile_add_phone'.format(route_prefix),
|
||||||
|
'{}/profile/add-phone'.format(instance_url_prefix),
|
||||||
|
request_method='POST')
|
||||||
|
config.add_view(cls, attr='profile_add_phone',
|
||||||
|
route_name='{}.profile_add_phone'.format(route_prefix),
|
||||||
|
renderer='json',
|
||||||
|
permission='people_profile.edit_person')
|
||||||
|
|
||||||
|
# profile - update phone
|
||||||
|
config.add_route('{}.profile_update_phone'.format(route_prefix),
|
||||||
|
'{}/profile/update-phone'.format(instance_url_prefix),
|
||||||
|
request_method='POST')
|
||||||
|
config.add_view(cls, attr='profile_update_phone',
|
||||||
|
route_name='{}.profile_update_phone'.format(route_prefix),
|
||||||
|
renderer='json',
|
||||||
|
permission='people_profile.edit_person')
|
||||||
|
|
||||||
|
# profile - delete phone
|
||||||
|
config.add_route('{}.profile_delete_phone'.format(route_prefix),
|
||||||
|
'{}/profile/delete-phone'.format(instance_url_prefix),
|
||||||
|
request_method='POST')
|
||||||
|
config.add_view(cls, attr='profile_delete_phone',
|
||||||
|
route_name='{}.profile_delete_phone'.format(route_prefix),
|
||||||
|
renderer='json',
|
||||||
|
permission='people_profile.edit_person')
|
||||||
|
|
||||||
|
# profile - set preferred phone
|
||||||
|
config.add_route('{}.profile_set_preferred_phone'.format(route_prefix),
|
||||||
|
'{}/profile/set-preferred-phone'.format(instance_url_prefix),
|
||||||
|
request_method='POST')
|
||||||
|
config.add_view(cls, attr='profile_set_preferred_phone',
|
||||||
|
route_name='{}.profile_set_preferred_phone'.format(route_prefix),
|
||||||
|
renderer='json',
|
||||||
|
permission='people_profile.edit_person')
|
||||||
|
|
||||||
|
# profile - add email
|
||||||
|
config.add_route('{}.profile_add_email'.format(route_prefix),
|
||||||
|
'{}/profile/add-email'.format(instance_url_prefix),
|
||||||
|
request_method='POST')
|
||||||
|
config.add_view(cls, attr='profile_add_email',
|
||||||
|
route_name='{}.profile_add_email'.format(route_prefix),
|
||||||
|
renderer='json',
|
||||||
|
permission='people_profile.edit_person')
|
||||||
|
|
||||||
|
# profile - update email
|
||||||
|
config.add_route('{}.profile_update_email'.format(route_prefix),
|
||||||
|
'{}/profile/update-email'.format(instance_url_prefix),
|
||||||
|
request_method='POST')
|
||||||
|
config.add_view(cls, attr='profile_update_email',
|
||||||
|
route_name='{}.profile_update_email'.format(route_prefix),
|
||||||
|
renderer='json',
|
||||||
|
permission='people_profile.edit_person')
|
||||||
|
|
||||||
|
# profile - delete email
|
||||||
|
config.add_route('{}.profile_delete_email'.format(route_prefix),
|
||||||
|
'{}/profile/delete-email'.format(instance_url_prefix),
|
||||||
|
request_method='POST')
|
||||||
|
config.add_view(cls, attr='profile_delete_email',
|
||||||
|
route_name='{}.profile_delete_email'.format(route_prefix),
|
||||||
|
renderer='json',
|
||||||
|
permission='people_profile.edit_person')
|
||||||
|
|
||||||
|
# profile - set preferred email
|
||||||
|
config.add_route('{}.profile_set_preferred_email'.format(route_prefix),
|
||||||
|
'{}/profile/set-preferred-email'.format(instance_url_prefix),
|
||||||
|
request_method='POST')
|
||||||
|
config.add_view(cls, attr='profile_set_preferred_email',
|
||||||
|
route_name='{}.profile_set_preferred_email'.format(route_prefix),
|
||||||
|
renderer='json',
|
||||||
|
permission='people_profile.edit_person')
|
||||||
|
|
||||||
|
# profile - edit address
|
||||||
|
config.add_route('{}.profile_edit_address'.format(route_prefix),
|
||||||
|
'{}/profile/edit-address'.format(instance_url_prefix),
|
||||||
|
request_method='POST')
|
||||||
|
config.add_view(cls, attr='profile_edit_address',
|
||||||
|
route_name='{}.profile_edit_address'.format(route_prefix),
|
||||||
|
renderer='json',
|
||||||
|
permission='people_profile.edit_person')
|
||||||
|
|
||||||
# profile - start employee
|
# profile - start employee
|
||||||
config.add_route('{}.profile_start_employee'.format(route_prefix), '{}/profile/start-employee'.format(instance_url_prefix),
|
config.add_route('{}.profile_start_employee'.format(route_prefix), '{}/profile/start-employee'.format(instance_url_prefix),
|
||||||
request_method='POST')
|
request_method='POST')
|
||||||
|
|
Loading…
Reference in a new issue