forked from CGM_Public/pretix_original
Add name scheme with salutation (#1779)
This commit is contained in:
@@ -222,6 +222,7 @@ class SimpleFunctionalMailTextPlaceholder(BaseMailTextPlaceholder):
|
||||
def get_available_placeholders(event, base_parameters):
|
||||
if 'order' in base_parameters:
|
||||
base_parameters.append('invoice_address')
|
||||
base_parameters.append('position_or_address')
|
||||
params = {}
|
||||
for r, val in register_mail_placeholders.send(sender=event):
|
||||
if not isinstance(val, (list, tuple)):
|
||||
@@ -241,6 +242,8 @@ def get_email_context(**kwargs):
|
||||
kwargs['invoice_address'] = kwargs['order'].invoice_address
|
||||
except InvoiceAddress.DoesNotExist:
|
||||
kwargs['invoice_address'] = InvoiceAddress()
|
||||
finally:
|
||||
kwargs.setdefault("position_or_address", kwargs['invoice_address'])
|
||||
ctx = {}
|
||||
for r, val in register_mail_placeholders.send(sender=event):
|
||||
if not isinstance(val, (list, tuple)):
|
||||
@@ -268,7 +271,8 @@ def get_best_name(position_or_address, parts=False):
|
||||
if isinstance(position_or_address, InvoiceAddress):
|
||||
if position_or_address.name:
|
||||
return position_or_address.name_parts if parts else position_or_address.name
|
||||
position_or_address = position_or_address.order.positions.exclude(attendee_name_cached="").exclude(attendee_name_cached__isnull=True).first()
|
||||
elif position_or_address.order:
|
||||
position_or_address = position_or_address.order.positions.exclude(attendee_name_cached="").exclude(attendee_name_cached__isnull=True).first()
|
||||
|
||||
if isinstance(position_or_address, OrderPosition):
|
||||
if position_or_address.attendee_name:
|
||||
|
||||
@@ -36,8 +36,8 @@ from pretix.base.i18n import language
|
||||
from pretix.base.models import InvoiceAddress, Question, QuestionOption
|
||||
from pretix.base.models.tax import EU_COUNTRIES, cc_to_vat_prefix
|
||||
from pretix.base.settings import (
|
||||
COUNTRIES_WITH_STATE_IN_ADDRESS, PERSON_NAME_SCHEMES,
|
||||
PERSON_NAME_TITLE_GROUPS,
|
||||
COUNTRIES_WITH_STATE_IN_ADDRESS, PERSON_NAME_SALUTATIONS,
|
||||
PERSON_NAME_SCHEMES, PERSON_NAME_TITLE_GROUPS,
|
||||
)
|
||||
from pretix.base.templatetags.rich_text import rich_text
|
||||
from pretix.control.forms import ExtFileField, SplitDateTimeField
|
||||
@@ -49,7 +49,7 @@ from pretix.presale.signals import question_form_fields
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
REQUIRED_NAME_PARTS = ['given_name', 'family_name', 'full_name']
|
||||
REQUIRED_NAME_PARTS = ['salutation', 'given_name', 'family_name', 'full_name']
|
||||
|
||||
|
||||
class NamePartsWidget(forms.MultiWidget):
|
||||
@@ -73,6 +73,8 @@ class NamePartsWidget(forms.MultiWidget):
|
||||
a['data-fname'] = fname
|
||||
if fname == 'title' and self.titles:
|
||||
widgets.append(Select(attrs=a, choices=[('', '')] + [(d, d) for d in self.titles[1]]))
|
||||
elif fname == 'salutation':
|
||||
widgets.append(Select(attrs=a, choices=[('', '---')] + [(s, s) for s in PERSON_NAME_SALUTATIONS]))
|
||||
else:
|
||||
widgets.append(self.widget(attrs=a))
|
||||
super().__init__(widgets, attrs)
|
||||
@@ -162,12 +164,18 @@ class NamePartsFormField(forms.MultiValueField):
|
||||
**d,
|
||||
choices=[('', '')] + [(d, d) for d in self.scheme_titles[1]]
|
||||
)
|
||||
field.part_name = fname
|
||||
fields.append(field)
|
||||
|
||||
elif fname == 'salutation':
|
||||
d = dict(defaults)
|
||||
d.pop('max_length', None)
|
||||
field = forms.ChoiceField(
|
||||
**d,
|
||||
choices=[('', '---')] + [(s, s) for s in PERSON_NAME_SALUTATIONS]
|
||||
)
|
||||
else:
|
||||
field = forms.CharField(**defaults)
|
||||
field.part_name = fname
|
||||
fields.append(field)
|
||||
field.part_name = fname
|
||||
fields.append(field)
|
||||
super().__init__(
|
||||
fields=fields, require_all_fields=False, *args, **kwargs
|
||||
)
|
||||
|
||||
@@ -1845,7 +1845,7 @@ PERSON_NAME_TITLE_GROUPS = OrderedDict([
|
||||
'Mx',
|
||||
'Dr',
|
||||
'Professor',
|
||||
'Sir'
|
||||
'Sir',
|
||||
))),
|
||||
('german_common', (_('Most common German titles'), (
|
||||
'Dr.',
|
||||
@@ -1853,9 +1853,16 @@ PERSON_NAME_TITLE_GROUPS = OrderedDict([
|
||||
'Prof. Dr.',
|
||||
)))
|
||||
])
|
||||
|
||||
PERSON_NAME_SALUTATIONS = [
|
||||
pgettext_lazy("person_name_salutation", "Ms"),
|
||||
pgettext_lazy("person_name_salutation", "Mr"),
|
||||
]
|
||||
|
||||
PERSON_NAME_SCHEMES = OrderedDict([
|
||||
('given_family', {
|
||||
'fields': (
|
||||
# field_name, label, weight for widget width
|
||||
('given_name', _('Given name'), 1),
|
||||
('family_name', _('Family name'), 1),
|
||||
),
|
||||
@@ -2010,6 +2017,24 @@ PERSON_NAME_SCHEMES = OrderedDict([
|
||||
'_scheme': 'full_transcription',
|
||||
},
|
||||
}),
|
||||
('salutation_title_given_family', {
|
||||
'fields': (
|
||||
('salutation', pgettext_lazy('person_name', 'Salutation'), 1),
|
||||
('title', pgettext_lazy('person_name', 'Title'), 1),
|
||||
('given_name', _('Given name'), 2),
|
||||
('family_name', _('Family name'), 2),
|
||||
),
|
||||
'concatenation': lambda d: ' '.join(
|
||||
str(p) for p in (d.get(key, '') for key in ["title", "given_name", "family_name"]) if p
|
||||
),
|
||||
'sample': {
|
||||
'salutation': pgettext_lazy('person_name_sample', 'Mr'),
|
||||
'title': pgettext_lazy('person_name_sample', 'Dr'),
|
||||
'given_name': pgettext_lazy('person_name_sample', 'John'),
|
||||
'family_name': pgettext_lazy('person_name_sample', 'Doe'),
|
||||
'_scheme': 'title_salutation_given_family',
|
||||
},
|
||||
}),
|
||||
])
|
||||
COUNTRIES_WITH_STATE_IN_ADDRESS = {
|
||||
# Source: http://www.bitboost.com/ref/international-address-formats.html
|
||||
@@ -2025,7 +2050,6 @@ COUNTRIES_WITH_STATE_IN_ADDRESS = {
|
||||
'US': (['State', 'Outlying area', 'District'], 'short'),
|
||||
}
|
||||
|
||||
|
||||
settings_hierarkey = Hierarkey(attribute_name='settings')
|
||||
|
||||
for k, v in DEFAULTS.items():
|
||||
@@ -2095,7 +2119,7 @@ class SettingsSandbox:
|
||||
def __delattr__(self, key: str) -> None:
|
||||
del self._event.settings[self._convert_key(key)]
|
||||
|
||||
def get(self, key: str, default: Any=None, as_type: type=str):
|
||||
def get(self, key: str, default: Any = None, as_type: type = str):
|
||||
return self._event.settings.get(self._convert_key(key), default=default, as_type=as_type)
|
||||
|
||||
def set(self, key: str, value: Any):
|
||||
|
||||
@@ -604,7 +604,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
def test_attendee_name_scheme(self):
|
||||
self.event.settings.set('attendee_names_asked', True)
|
||||
self.event.settings.set('attendee_names_required', True)
|
||||
self.event.settings.set('name_scheme', 'title_given_middle_family')
|
||||
self.event.settings.set('name_scheme', 'salutation_title_given_family')
|
||||
with scopes_disabled():
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
@@ -612,17 +612,16 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
)
|
||||
response = self.client.get('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
doc = BeautifulSoup(response.rendered_content, "lxml")
|
||||
self.assertEqual(len(doc.select('input[name="%s-attendee_name_parts_0"]' % cr1.id)), 1)
|
||||
self.assertEqual(len(doc.select('select[name="%s-attendee_name_parts_0"]' % cr1.id)), 1)
|
||||
self.assertEqual(len(doc.select('input[name="%s-attendee_name_parts_1"]' % cr1.id)), 1)
|
||||
self.assertEqual(len(doc.select('input[name="%s-attendee_name_parts_2"]' % cr1.id)), 1)
|
||||
self.assertEqual(len(doc.select('input[name="%s-attendee_name_parts_3"]' % cr1.id)), 1)
|
||||
|
||||
# Not all required fields filled out, expect failure
|
||||
response = self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'%s-attendee_name_parts_0' % cr1.id: 'Mr',
|
||||
'%s-attendee_name_parts_1' % cr1.id: 'John',
|
||||
'%s-attendee_name_parts_2' % cr1.id: 'F',
|
||||
'%s-attendee_name_parts_3' % cr1.id: 'Kennedy',
|
||||
'%s-attendee_name_parts_1' % cr1.id: '',
|
||||
'%s-attendee_name_parts_2' % cr1.id: 'John',
|
||||
'%s-attendee_name_parts_3' % cr1.id: 'Doe',
|
||||
'email': 'admin@localhost'
|
||||
})
|
||||
self.assertRedirects(response, '/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug),
|
||||
@@ -630,13 +629,13 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
|
||||
with scopes_disabled():
|
||||
cr1 = CartPosition.objects.get(id=cr1.id)
|
||||
self.assertEqual(cr1.attendee_name, 'Mr John F Kennedy')
|
||||
self.assertEqual(cr1.attendee_name, 'John Doe')
|
||||
self.assertEqual(cr1.attendee_name_parts, {
|
||||
'salutation': 'Mr',
|
||||
'title': '',
|
||||
'given_name': 'John',
|
||||
'title': 'Mr',
|
||||
'middle_name': 'F',
|
||||
'family_name': 'Kennedy',
|
||||
"_scheme": "title_given_middle_family"
|
||||
'family_name': 'Doe',
|
||||
"_scheme": "salutation_title_given_family"
|
||||
})
|
||||
|
||||
def test_attendee_name_optional(self):
|
||||
|
||||
Reference in New Issue
Block a user