Add basic CRUD for Person "preferred first name"

only shown if config flag says so
This commit is contained in:
Lance Edgar 2024-04-01 18:05:27 -05:00
parent cdc857065b
commit 1889f7d269
3 changed files with 91 additions and 17 deletions

View file

@ -5,6 +5,9 @@ CHANGELOG
Unreleased
----------
* Add basic CRUD for Person "preferred first name".
0.9.89 (2024-03-27)
-------------------

View file

@ -91,6 +91,12 @@
<span>{{ person.first_name }}</span>
</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">
<span>{{ person.middle_name }}</span>
</b-field>
@ -118,11 +124,25 @@
</header>
<section class="modal-card-body">
<b-field label="First Name">
<b-input v-model.trim="editNameFirst"
:maxlength="maxLengths.person_first_name || null">
</b-input>
<b-field grouped>
<b-field label="First Name" expanded>
<b-input v-model.trim="editNameFirst"
:maxlength="maxLengths.person_first_name || null">
</b-input>
</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-input v-model.trim="editNameMiddle"
:maxlength="maxLengths.person_middle_name || null">
@ -1497,6 +1517,9 @@
% if request.has_perm('people_profile.edit_person'):
editNameShowDialog: false,
editNameFirst: null,
% if use_preferred_first_name:
editNameFirstPreferred: null,
% endif
editNameMiddle: null,
editNameLast: null,
@ -1590,6 +1613,9 @@
editNameInit() {
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.editNameLast = this.person.last_name
this.editNameShowDialog = true
@ -1599,6 +1625,9 @@
let url = '${url('people.profile_edit_name', uuid=person.uuid)}'
let params = {
first_name: this.editNameFirst,
% if use_preferred_first_name:
preferred_first_name: this.editNameFirstPreferred,
% endif
middle_name: this.editNameMiddle,
last_name: this.editNameLast,
}

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2023 Lance Edgar
# Copyright © 2010-2024 Lance Edgar
#
# This file is part of Rattail.
#
@ -32,7 +32,8 @@ import sqlalchemy as sa
from sqlalchemy import orm
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.time import localtime
from rattail.util import simple_error
@ -53,7 +54,7 @@ class PersonView(MasterView):
"""
Master view for the Person class.
"""
model_class = model.Person
model_class = Person
model_title_plural = "People"
route_prefix = 'people'
touchable = True
@ -210,6 +211,7 @@ class PersonView(MasterView):
c="MR")
def get_instance(self):
model = self.model
# TODO: I don't recall why this fallback check for a vendor contact
# exists here, but leaving it intact for now.
key = self.request.matchdict['uuid']
@ -237,6 +239,13 @@ class PersonView(MasterView):
return True
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):
if data is None:
data = form.validated
@ -248,6 +257,9 @@ class PersonView(MasterView):
names = {}
if 'first_name' in form:
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:
names['middle'] = data['middle_name']
if 'last_name' in form:
@ -292,6 +304,8 @@ class PersonView(MasterView):
In addition to "touching" the person proper, we also "touch" each
contact info record associated with them.
"""
model = self.model
# touch person, as per usual
super().touch_instance(person)
@ -426,6 +440,7 @@ class PersonView(MasterView):
return ""
def get_version_child_classes(self):
model = self.model
return [
(model.PersonPhoneNumber, 'parent_uuid'),
(model.PersonEmailAddress, 'parent_uuid'),
@ -474,6 +489,7 @@ class PersonView(MasterView):
'expose_customer_people': self.customers_should_expose_people(),
'expose_customer_shoppers': self.customers_should_expose_shoppers(),
'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'):
@ -552,7 +568,7 @@ class PersonView(MasterView):
def get_max_lengths(self):
model = self.model
return {
lengths = {
'person_first_name': maxlen(model.Person.first_name),
'person_middle_name': maxlen(model.Person.middle_name),
'person_last_name': maxlen(model.Person.last_name),
@ -562,6 +578,9 @@ class PersonView(MasterView):
'address_state': maxlen(model.PersonMailingAddress.state),
'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):
"""
@ -606,6 +625,9 @@ class PersonView(MasterView):
'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:
context['address'] = self.get_context_address(person.address)
@ -871,10 +893,16 @@ class PersonView(MasterView):
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'])
kw = {
'first': data['first_name'],
'middle': data['middle_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()
return self.profile_changed_response(person)
@ -913,6 +941,7 @@ class PersonView(MasterView):
"""
View which updates a phone number for the person.
"""
model = self.model
person = self.get_instance()
data = dict(self.request.json_body)
@ -940,6 +969,7 @@ class PersonView(MasterView):
"""
View which allows a person's phone number to be deleted.
"""
model = self.model
person = self.get_instance()
data = dict(self.request.json_body)
@ -960,6 +990,7 @@ class PersonView(MasterView):
"""
View which allows a person's "preferred" phone to be set.
"""
model = self.model
person = self.get_instance()
data = dict(self.request.json_body)
@ -1016,6 +1047,7 @@ class PersonView(MasterView):
"""
View which updates an email address for the person.
"""
model = self.model
person = self.get_instance()
data = dict(self.request.json_body)
@ -1039,6 +1071,7 @@ class PersonView(MasterView):
"""
View which allows a person's email address to be deleted.
"""
model = self.model
person = self.get_instance()
data = dict(self.request.json_body)
@ -1059,6 +1092,7 @@ class PersonView(MasterView):
"""
View which allows a person's "preferred" email to be set.
"""
model = self.model
person = self.get_instance()
data = dict(self.request.json_body)
@ -1192,6 +1226,7 @@ class PersonView(MasterView):
"""
AJAX view for updating an employee history record.
"""
model = self.model
person = self.get_instance()
employee = person.employee
@ -1459,6 +1494,7 @@ class PersonView(MasterView):
return self.profile_changed_response(person)
def create_note(self, person, form):
model = self.model
note = model.PersonNote()
note.type = form.validated['note_type']
note.subject = form.validated['note_subject']
@ -1478,6 +1514,7 @@ class PersonView(MasterView):
return self.profile_changed_response(person)
def update_note(self, person, form):
model = self.model
note = self.Session.get(model.PersonNote, form.validated['uuid'])
note.subject = form.validated['note_subject']
note.text = form.validated['note_text']
@ -1494,10 +1531,12 @@ class PersonView(MasterView):
return self.profile_changed_response(person)
def delete_note(self, person, form):
model = self.model
note = self.Session.get(model.PersonNote, form.validated['uuid'])
self.Session.delete(note)
def make_user(self):
model = self.model
uuid = self.request.POST['person_uuid']
person = self.Session.get(model.Person, uuid)
if not person:
@ -1815,7 +1854,7 @@ class PersonNoteView(MasterView):
"""
Master view for the PersonNote class.
"""
model_class = model.PersonNote
model_class = PersonNote
route_prefix = 'person_notes'
url_prefix = '/people/notes'
has_versions = True
@ -1842,6 +1881,7 @@ class PersonNoteView(MasterView):
def configure_grid(self, g):
super().configure_grid(g)
model = self.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']
person_uuid = kw['person_uuid']
def validate(node, value):
note = session.get(model.PersonNote, value)
note = session.get(PersonNote, value)
if not note:
raise colander.Invalid(node, "Note not found")
if note.person.uuid != person_uuid:
@ -1906,7 +1946,7 @@ class MergePeopleRequestView(MasterView):
"""
Master view for the MergePeopleRequest class.
"""
model_class = model.MergePeopleRequest
model_class = MergePeopleRequest
route_prefix = 'people_merge_requests'
url_prefix = '/people/merge-requests'
creatable = False
@ -1950,8 +1990,9 @@ class MergePeopleRequestView(MasterView):
g.set_link('keeping_uuid')
def render_referenced_person_name(self, merge_request, field):
model = self.model
uuid = getattr(merge_request, field)
person = self.Session.get(self.model.Person, uuid)
person = self.Session.get(model.Person, uuid)
if person:
return str(person)
return "(person not found)"
@ -1971,8 +2012,9 @@ class MergePeopleRequestView(MasterView):
f.set_renderer('keeping_uuid', self.render_referenced_person)
def render_referenced_person(self, merge_request, field):
model = self.model
uuid = getattr(merge_request, field)
person = self.Session.get(self.model.Person, uuid)
person = self.Session.get(model.Person, uuid)
if person:
text = str(person)
url = self.request.route_url('people.view', uuid=person.uuid)