Add basic CRUD for Person "preferred first name"
only shown if config flag says so
This commit is contained in:
parent
cdc857065b
commit
1889f7d269
|
@ -5,6 +5,9 @@ CHANGELOG
|
||||||
Unreleased
|
Unreleased
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
* Add basic CRUD for Person "preferred first name".
|
||||||
|
|
||||||
|
|
||||||
0.9.89 (2024-03-27)
|
0.9.89 (2024-03-27)
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,12 @@
|
||||||
<span>{{ person.first_name }}</span>
|
<span>{{ person.first_name }}</span>
|
||||||
</b-field>
|
</b-field>
|
||||||
|
|
||||||
|
% if use_preferred_first_name:
|
||||||
|
<b-field horizontal label="Preferred First Name">
|
||||||
|
<span>{{ person.preferred_first_name }}</span>
|
||||||
|
</b-field>
|
||||||
|
% endif
|
||||||
|
|
||||||
<b-field horizontal label="Middle Name">
|
<b-field horizontal label="Middle Name">
|
||||||
<span>{{ person.middle_name }}</span>
|
<span>{{ person.middle_name }}</span>
|
||||||
</b-field>
|
</b-field>
|
||||||
|
@ -118,11 +124,25 @@
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<section class="modal-card-body">
|
<section class="modal-card-body">
|
||||||
<b-field label="First Name">
|
|
||||||
|
<b-field grouped>
|
||||||
|
|
||||||
|
<b-field label="First Name" expanded>
|
||||||
<b-input v-model.trim="editNameFirst"
|
<b-input v-model.trim="editNameFirst"
|
||||||
:maxlength="maxLengths.person_first_name || null">
|
:maxlength="maxLengths.person_first_name || null">
|
||||||
</b-input>
|
</b-input>
|
||||||
</b-field>
|
</b-field>
|
||||||
|
|
||||||
|
% if use_preferred_first_name:
|
||||||
|
<b-field label="Preferred First Name" expanded>
|
||||||
|
<b-input v-model.trim="editNameFirstPreferred"
|
||||||
|
:maxlength="maxLengths.person_preferred_first_name || null">
|
||||||
|
</b-input>
|
||||||
|
</b-field>
|
||||||
|
% endif
|
||||||
|
|
||||||
|
</b-field>
|
||||||
|
|
||||||
<b-field label="Middle Name">
|
<b-field label="Middle Name">
|
||||||
<b-input v-model.trim="editNameMiddle"
|
<b-input v-model.trim="editNameMiddle"
|
||||||
:maxlength="maxLengths.person_middle_name || null">
|
:maxlength="maxLengths.person_middle_name || null">
|
||||||
|
@ -1497,6 +1517,9 @@
|
||||||
% if request.has_perm('people_profile.edit_person'):
|
% if request.has_perm('people_profile.edit_person'):
|
||||||
editNameShowDialog: false,
|
editNameShowDialog: false,
|
||||||
editNameFirst: null,
|
editNameFirst: null,
|
||||||
|
% if use_preferred_first_name:
|
||||||
|
editNameFirstPreferred: null,
|
||||||
|
% endif
|
||||||
editNameMiddle: null,
|
editNameMiddle: null,
|
||||||
editNameLast: null,
|
editNameLast: null,
|
||||||
|
|
||||||
|
@ -1590,6 +1613,9 @@
|
||||||
|
|
||||||
editNameInit() {
|
editNameInit() {
|
||||||
this.editNameFirst = this.person.first_name
|
this.editNameFirst = this.person.first_name
|
||||||
|
% if use_preferred_first_name:
|
||||||
|
this.editNameFirstPreferred = this.person.preferred_first_name
|
||||||
|
% endif
|
||||||
this.editNameMiddle = this.person.middle_name
|
this.editNameMiddle = this.person.middle_name
|
||||||
this.editNameLast = this.person.last_name
|
this.editNameLast = this.person.last_name
|
||||||
this.editNameShowDialog = true
|
this.editNameShowDialog = true
|
||||||
|
@ -1599,6 +1625,9 @@
|
||||||
let url = '${url('people.profile_edit_name', uuid=person.uuid)}'
|
let url = '${url('people.profile_edit_name', uuid=person.uuid)}'
|
||||||
let params = {
|
let params = {
|
||||||
first_name: this.editNameFirst,
|
first_name: this.editNameFirst,
|
||||||
|
% if use_preferred_first_name:
|
||||||
|
preferred_first_name: this.editNameFirstPreferred,
|
||||||
|
% endif
|
||||||
middle_name: this.editNameMiddle,
|
middle_name: this.editNameMiddle,
|
||||||
last_name: this.editNameLast,
|
last_name: this.editNameLast,
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2023 Lance Edgar
|
# Copyright © 2010-2024 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -32,7 +32,8 @@ import sqlalchemy as sa
|
||||||
from sqlalchemy import orm
|
from sqlalchemy import orm
|
||||||
import sqlalchemy_continuum as continuum
|
import sqlalchemy_continuum as continuum
|
||||||
|
|
||||||
from rattail.db import model, api
|
from rattail.db import api
|
||||||
|
from rattail.db.model import Person, PersonNote, MergePeopleRequest
|
||||||
from rattail.db.util import maxlen
|
from rattail.db.util import maxlen
|
||||||
from rattail.time import localtime
|
from rattail.time import localtime
|
||||||
from rattail.util import simple_error
|
from rattail.util import simple_error
|
||||||
|
@ -53,7 +54,7 @@ class PersonView(MasterView):
|
||||||
"""
|
"""
|
||||||
Master view for the Person class.
|
Master view for the Person class.
|
||||||
"""
|
"""
|
||||||
model_class = model.Person
|
model_class = Person
|
||||||
model_title_plural = "People"
|
model_title_plural = "People"
|
||||||
route_prefix = 'people'
|
route_prefix = 'people'
|
||||||
touchable = True
|
touchable = True
|
||||||
|
@ -210,6 +211,7 @@ class PersonView(MasterView):
|
||||||
c="MR")
|
c="MR")
|
||||||
|
|
||||||
def get_instance(self):
|
def get_instance(self):
|
||||||
|
model = self.model
|
||||||
# TODO: I don't recall why this fallback check for a vendor contact
|
# TODO: I don't recall why this fallback check for a vendor contact
|
||||||
# exists here, but leaving it intact for now.
|
# exists here, but leaving it intact for now.
|
||||||
key = self.request.matchdict['uuid']
|
key = self.request.matchdict['uuid']
|
||||||
|
@ -237,6 +239,13 @@ class PersonView(MasterView):
|
||||||
return True
|
return True
|
||||||
return not self.is_person_protected(person)
|
return not self.is_person_protected(person)
|
||||||
|
|
||||||
|
def configure_form(self, f):
|
||||||
|
super().configure_form(f)
|
||||||
|
|
||||||
|
# preferred_first_name
|
||||||
|
if self.people_handler.should_use_preferred_first_name():
|
||||||
|
f.insert_after('first_name', 'preferred_first_name')
|
||||||
|
|
||||||
def objectify(self, form, data=None):
|
def objectify(self, form, data=None):
|
||||||
if data is None:
|
if data is None:
|
||||||
data = form.validated
|
data = form.validated
|
||||||
|
@ -248,6 +257,9 @@ class PersonView(MasterView):
|
||||||
names = {}
|
names = {}
|
||||||
if 'first_name' in form:
|
if 'first_name' in form:
|
||||||
names['first'] = data['first_name']
|
names['first'] = data['first_name']
|
||||||
|
if self.people_handler.should_use_preferred_first_name():
|
||||||
|
if 'preferred_first_name' in form:
|
||||||
|
names['preferred_first'] = data['preferred_first_name']
|
||||||
if 'middle_name' in form:
|
if 'middle_name' in form:
|
||||||
names['middle'] = data['middle_name']
|
names['middle'] = data['middle_name']
|
||||||
if 'last_name' in form:
|
if 'last_name' in form:
|
||||||
|
@ -292,6 +304,8 @@ class PersonView(MasterView):
|
||||||
In addition to "touching" the person proper, we also "touch" each
|
In addition to "touching" the person proper, we also "touch" each
|
||||||
contact info record associated with them.
|
contact info record associated with them.
|
||||||
"""
|
"""
|
||||||
|
model = self.model
|
||||||
|
|
||||||
# touch person, as per usual
|
# touch person, as per usual
|
||||||
super().touch_instance(person)
|
super().touch_instance(person)
|
||||||
|
|
||||||
|
@ -426,6 +440,7 @@ class PersonView(MasterView):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def get_version_child_classes(self):
|
def get_version_child_classes(self):
|
||||||
|
model = self.model
|
||||||
return [
|
return [
|
||||||
(model.PersonPhoneNumber, 'parent_uuid'),
|
(model.PersonPhoneNumber, 'parent_uuid'),
|
||||||
(model.PersonEmailAddress, 'parent_uuid'),
|
(model.PersonEmailAddress, 'parent_uuid'),
|
||||||
|
@ -474,6 +489,7 @@ class PersonView(MasterView):
|
||||||
'expose_customer_people': self.customers_should_expose_people(),
|
'expose_customer_people': self.customers_should_expose_people(),
|
||||||
'expose_customer_shoppers': self.customers_should_expose_shoppers(),
|
'expose_customer_shoppers': self.customers_should_expose_shoppers(),
|
||||||
'max_one_member': app.get_membership_handler().max_one_per_person(),
|
'max_one_member': app.get_membership_handler().max_one_per_person(),
|
||||||
|
'use_preferred_first_name': self.people_handler.should_use_preferred_first_name(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.request.has_perm('people_profile.view_versions'):
|
if self.request.has_perm('people_profile.view_versions'):
|
||||||
|
@ -552,7 +568,7 @@ class PersonView(MasterView):
|
||||||
|
|
||||||
def get_max_lengths(self):
|
def get_max_lengths(self):
|
||||||
model = self.model
|
model = self.model
|
||||||
return {
|
lengths = {
|
||||||
'person_first_name': maxlen(model.Person.first_name),
|
'person_first_name': maxlen(model.Person.first_name),
|
||||||
'person_middle_name': maxlen(model.Person.middle_name),
|
'person_middle_name': maxlen(model.Person.middle_name),
|
||||||
'person_last_name': maxlen(model.Person.last_name),
|
'person_last_name': maxlen(model.Person.last_name),
|
||||||
|
@ -562,6 +578,9 @@ class PersonView(MasterView):
|
||||||
'address_state': maxlen(model.PersonMailingAddress.state),
|
'address_state': maxlen(model.PersonMailingAddress.state),
|
||||||
'address_zipcode': maxlen(model.PersonMailingAddress.zipcode),
|
'address_zipcode': maxlen(model.PersonMailingAddress.zipcode),
|
||||||
}
|
}
|
||||||
|
if self.people_handler.should_use_preferred_first_name():
|
||||||
|
lengths['person_preferred_first_name'] = maxlen(model.Person.preferred_first_name)
|
||||||
|
return lengths
|
||||||
|
|
||||||
def get_phone_type_options(self):
|
def get_phone_type_options(self):
|
||||||
"""
|
"""
|
||||||
|
@ -606,6 +625,9 @@ class PersonView(MasterView):
|
||||||
'dynamic_content_title': self.get_context_content_title(person),
|
'dynamic_content_title': self.get_context_content_title(person),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.people_handler.should_use_preferred_first_name():
|
||||||
|
context['preferred_first_name'] = person.preferred_first_name
|
||||||
|
|
||||||
if person.address:
|
if person.address:
|
||||||
context['address'] = self.get_context_address(person.address)
|
context['address'] = self.get_context_address(person.address)
|
||||||
|
|
||||||
|
@ -871,10 +893,16 @@ class PersonView(MasterView):
|
||||||
person = self.get_instance()
|
person = self.get_instance()
|
||||||
data = dict(self.request.json_body)
|
data = dict(self.request.json_body)
|
||||||
|
|
||||||
self.handler.update_names(person,
|
kw = {
|
||||||
first=data['first_name'],
|
'first': data['first_name'],
|
||||||
middle=data['middle_name'],
|
'middle': data['middle_name'],
|
||||||
last=data['last_name'])
|
'last': data['last_name'],
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.people_handler.should_use_preferred_first_name():
|
||||||
|
kw['preferred_first'] = data['preferred_first_name']
|
||||||
|
|
||||||
|
self.handler.update_names(person, **kw)
|
||||||
|
|
||||||
self.Session.flush()
|
self.Session.flush()
|
||||||
return self.profile_changed_response(person)
|
return self.profile_changed_response(person)
|
||||||
|
@ -913,6 +941,7 @@ class PersonView(MasterView):
|
||||||
"""
|
"""
|
||||||
View which updates a phone number for the person.
|
View which updates a phone number for the person.
|
||||||
"""
|
"""
|
||||||
|
model = self.model
|
||||||
person = self.get_instance()
|
person = self.get_instance()
|
||||||
data = dict(self.request.json_body)
|
data = dict(self.request.json_body)
|
||||||
|
|
||||||
|
@ -940,6 +969,7 @@ class PersonView(MasterView):
|
||||||
"""
|
"""
|
||||||
View which allows a person's phone number to be deleted.
|
View which allows a person's phone number to be deleted.
|
||||||
"""
|
"""
|
||||||
|
model = self.model
|
||||||
person = self.get_instance()
|
person = self.get_instance()
|
||||||
data = dict(self.request.json_body)
|
data = dict(self.request.json_body)
|
||||||
|
|
||||||
|
@ -960,6 +990,7 @@ class PersonView(MasterView):
|
||||||
"""
|
"""
|
||||||
View which allows a person's "preferred" phone to be set.
|
View which allows a person's "preferred" phone to be set.
|
||||||
"""
|
"""
|
||||||
|
model = self.model
|
||||||
person = self.get_instance()
|
person = self.get_instance()
|
||||||
data = dict(self.request.json_body)
|
data = dict(self.request.json_body)
|
||||||
|
|
||||||
|
@ -1016,6 +1047,7 @@ class PersonView(MasterView):
|
||||||
"""
|
"""
|
||||||
View which updates an email address for the person.
|
View which updates an email address for the person.
|
||||||
"""
|
"""
|
||||||
|
model = self.model
|
||||||
person = self.get_instance()
|
person = self.get_instance()
|
||||||
data = dict(self.request.json_body)
|
data = dict(self.request.json_body)
|
||||||
|
|
||||||
|
@ -1039,6 +1071,7 @@ class PersonView(MasterView):
|
||||||
"""
|
"""
|
||||||
View which allows a person's email address to be deleted.
|
View which allows a person's email address to be deleted.
|
||||||
"""
|
"""
|
||||||
|
model = self.model
|
||||||
person = self.get_instance()
|
person = self.get_instance()
|
||||||
data = dict(self.request.json_body)
|
data = dict(self.request.json_body)
|
||||||
|
|
||||||
|
@ -1059,6 +1092,7 @@ class PersonView(MasterView):
|
||||||
"""
|
"""
|
||||||
View which allows a person's "preferred" email to be set.
|
View which allows a person's "preferred" email to be set.
|
||||||
"""
|
"""
|
||||||
|
model = self.model
|
||||||
person = self.get_instance()
|
person = self.get_instance()
|
||||||
data = dict(self.request.json_body)
|
data = dict(self.request.json_body)
|
||||||
|
|
||||||
|
@ -1192,6 +1226,7 @@ class PersonView(MasterView):
|
||||||
"""
|
"""
|
||||||
AJAX view for updating an employee history record.
|
AJAX view for updating an employee history record.
|
||||||
"""
|
"""
|
||||||
|
model = self.model
|
||||||
person = self.get_instance()
|
person = self.get_instance()
|
||||||
employee = person.employee
|
employee = person.employee
|
||||||
|
|
||||||
|
@ -1459,6 +1494,7 @@ class PersonView(MasterView):
|
||||||
return self.profile_changed_response(person)
|
return self.profile_changed_response(person)
|
||||||
|
|
||||||
def create_note(self, person, form):
|
def create_note(self, person, form):
|
||||||
|
model = self.model
|
||||||
note = model.PersonNote()
|
note = model.PersonNote()
|
||||||
note.type = form.validated['note_type']
|
note.type = form.validated['note_type']
|
||||||
note.subject = form.validated['note_subject']
|
note.subject = form.validated['note_subject']
|
||||||
|
@ -1478,6 +1514,7 @@ class PersonView(MasterView):
|
||||||
return self.profile_changed_response(person)
|
return self.profile_changed_response(person)
|
||||||
|
|
||||||
def update_note(self, person, form):
|
def update_note(self, person, form):
|
||||||
|
model = self.model
|
||||||
note = self.Session.get(model.PersonNote, form.validated['uuid'])
|
note = self.Session.get(model.PersonNote, form.validated['uuid'])
|
||||||
note.subject = form.validated['note_subject']
|
note.subject = form.validated['note_subject']
|
||||||
note.text = form.validated['note_text']
|
note.text = form.validated['note_text']
|
||||||
|
@ -1494,10 +1531,12 @@ class PersonView(MasterView):
|
||||||
return self.profile_changed_response(person)
|
return self.profile_changed_response(person)
|
||||||
|
|
||||||
def delete_note(self, person, form):
|
def delete_note(self, person, form):
|
||||||
|
model = self.model
|
||||||
note = self.Session.get(model.PersonNote, form.validated['uuid'])
|
note = self.Session.get(model.PersonNote, form.validated['uuid'])
|
||||||
self.Session.delete(note)
|
self.Session.delete(note)
|
||||||
|
|
||||||
def make_user(self):
|
def make_user(self):
|
||||||
|
model = self.model
|
||||||
uuid = self.request.POST['person_uuid']
|
uuid = self.request.POST['person_uuid']
|
||||||
person = self.Session.get(model.Person, uuid)
|
person = self.Session.get(model.Person, uuid)
|
||||||
if not person:
|
if not person:
|
||||||
|
@ -1815,7 +1854,7 @@ class PersonNoteView(MasterView):
|
||||||
"""
|
"""
|
||||||
Master view for the PersonNote class.
|
Master view for the PersonNote class.
|
||||||
"""
|
"""
|
||||||
model_class = model.PersonNote
|
model_class = PersonNote
|
||||||
route_prefix = 'person_notes'
|
route_prefix = 'person_notes'
|
||||||
url_prefix = '/people/notes'
|
url_prefix = '/people/notes'
|
||||||
has_versions = True
|
has_versions = True
|
||||||
|
@ -1842,6 +1881,7 @@ class PersonNoteView(MasterView):
|
||||||
|
|
||||||
def configure_grid(self, g):
|
def configure_grid(self, g):
|
||||||
super().configure_grid(g)
|
super().configure_grid(g)
|
||||||
|
model = self.model
|
||||||
|
|
||||||
# person
|
# person
|
||||||
g.set_joiner('person', lambda q: q.join(model.Person,
|
g.set_joiner('person', lambda q: q.join(model.Person,
|
||||||
|
@ -1881,7 +1921,7 @@ def valid_note_uuid(node, kw):
|
||||||
session = kw['session']
|
session = kw['session']
|
||||||
person_uuid = kw['person_uuid']
|
person_uuid = kw['person_uuid']
|
||||||
def validate(node, value):
|
def validate(node, value):
|
||||||
note = session.get(model.PersonNote, value)
|
note = session.get(PersonNote, value)
|
||||||
if not note:
|
if not note:
|
||||||
raise colander.Invalid(node, "Note not found")
|
raise colander.Invalid(node, "Note not found")
|
||||||
if note.person.uuid != person_uuid:
|
if note.person.uuid != person_uuid:
|
||||||
|
@ -1906,7 +1946,7 @@ class MergePeopleRequestView(MasterView):
|
||||||
"""
|
"""
|
||||||
Master view for the MergePeopleRequest class.
|
Master view for the MergePeopleRequest class.
|
||||||
"""
|
"""
|
||||||
model_class = model.MergePeopleRequest
|
model_class = MergePeopleRequest
|
||||||
route_prefix = 'people_merge_requests'
|
route_prefix = 'people_merge_requests'
|
||||||
url_prefix = '/people/merge-requests'
|
url_prefix = '/people/merge-requests'
|
||||||
creatable = False
|
creatable = False
|
||||||
|
@ -1950,8 +1990,9 @@ class MergePeopleRequestView(MasterView):
|
||||||
g.set_link('keeping_uuid')
|
g.set_link('keeping_uuid')
|
||||||
|
|
||||||
def render_referenced_person_name(self, merge_request, field):
|
def render_referenced_person_name(self, merge_request, field):
|
||||||
|
model = self.model
|
||||||
uuid = getattr(merge_request, field)
|
uuid = getattr(merge_request, field)
|
||||||
person = self.Session.get(self.model.Person, uuid)
|
person = self.Session.get(model.Person, uuid)
|
||||||
if person:
|
if person:
|
||||||
return str(person)
|
return str(person)
|
||||||
return "(person not found)"
|
return "(person not found)"
|
||||||
|
@ -1971,8 +2012,9 @@ class MergePeopleRequestView(MasterView):
|
||||||
f.set_renderer('keeping_uuid', self.render_referenced_person)
|
f.set_renderer('keeping_uuid', self.render_referenced_person)
|
||||||
|
|
||||||
def render_referenced_person(self, merge_request, field):
|
def render_referenced_person(self, merge_request, field):
|
||||||
|
model = self.model
|
||||||
uuid = getattr(merge_request, field)
|
uuid = getattr(merge_request, field)
|
||||||
person = self.Session.get(self.model.Person, uuid)
|
person = self.Session.get(model.Person, uuid)
|
||||||
if person:
|
if person:
|
||||||
text = str(person)
|
text = str(person)
|
||||||
url = self.request.route_url('people.view', uuid=person.uuid)
|
url = self.request.route_url('people.view', uuid=person.uuid)
|
||||||
|
|
Loading…
Reference in a new issue