Fix #978 -- Allow to split names (#1049)

- [x] attendee names
- [x] Invoice address names
- [x] Data migration
- [x] API serializers
  - [x] orderposition
  - [x] cartposition
  - [x] invoiceaddress
  - [x] checkinlistposition
- [x] position API search
- [x] invoice API search
- [x] business/individual required toggle
- [x] Split columns in CSV exports
- [x] ticket editor
- [x] shredder
- [x] ticket/invoice sample data
- [x] order search
- [x] Handle changed naming scheme
- [x] tests
- [x] make use in:
  - [x] Boabee
  - [x] Certificate download order
  - [x] Badge download order
  - [x] Ticket download order
- [x] Document new MySQL requirement
- [x] Plugins
This commit is contained in:
Raphael Michel
2018-11-05 15:43:21 +01:00
committed by GitHub
parent 7039374588
commit 94be46ffdb
71 changed files with 1219 additions and 244 deletions

View File

@@ -75,7 +75,7 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
REQUIRED_FIELDS = []
email = models.EmailField(unique=True, db_index=True, null=True, blank=True,
verbose_name=_('E-mail'))
verbose_name=_('E-mail'), max_length=190)
fullname = models.CharField(max_length=255, blank=True, null=True,
verbose_name=_('Full name'))
is_active = models.BooleanField(default=True,

View File

@@ -26,10 +26,12 @@ from django.utils.timezone import make_aware, now
from django.utils.translation import pgettext_lazy, ugettext_lazy as _
from django_countries.fields import CountryField
from i18nfield.strings import LazyI18nString
from jsonfallback.fields import FallbackJSONField
from pretix.base.i18n import language
from pretix.base.models import User
from pretix.base.reldate import RelativeDateWrapper
from pretix.base.settings import PERSON_NAME_SCHEMES
from .base import LockModel, LoggedModel
from .event import Event, SubEvent
@@ -699,8 +701,10 @@ class AbstractPosition(models.Model):
:type expires: datetime
:param price: The price of this item
:type price: decimal.Decimal
:param attendee_name: The attendee's name, if entered.
:type attendee_name: str
:param attendee_name_parts: The parts of the attendee's name, if entered.
:type attendee_name_parts: str
:param attendee_name_cached: The concatenated version of the attendee's name, if entered.
:type attendee_name_cached: str
:param attendee_email: The attendee's email, if entered.
:type attendee_email: str
:param voucher: A voucher that has been applied to this sale
@@ -729,12 +733,15 @@ class AbstractPosition(models.Model):
decimal_places=2, max_digits=10,
verbose_name=_("Price")
)
attendee_name = models.CharField(
attendee_name_cached = models.CharField(
max_length=255,
verbose_name=_("Attendee name"),
blank=True, null=True,
help_text=_("Empty, if this product is not an admission ticket")
)
attendee_name_parts = FallbackJSONField(
blank=True, default=dict
)
attendee_email = models.EmailField(
verbose_name=_("Attendee email"),
blank=True, null=True,
@@ -797,6 +804,24 @@ class AbstractPosition(models.Model):
if self.variation is None
else self.variation.quotas.filter(subevent=self.subevent))
def save(self, *args, **kwargs):
self.attendee_name_cached = self.attendee_name
if self.attendee_name_parts is None:
self.attendee_name_parts = {}
super().save(*args, **kwargs)
@property
def attendee_name(self):
if not self.attendee_name_parts:
return None
if '_legacy' in self.attendee_name_parts:
return self.attendee_name_parts['_legacy']
if '_scheme' in self.attendee_name_parts:
scheme = PERSON_NAME_SCHEMES[self.attendee_name_parts['_scheme']]
else:
scheme = PERSON_NAME_SCHEMES[self.event.settings.name_scheme]
return scheme['concatenation'](self.attendee_name_parts).strip()
class OrderPayment(models.Model):
"""
@@ -1482,6 +1507,10 @@ class OrderPosition(AbstractPosition):
self.pseudonymization_id = code
return
@property
def event(self):
return self.order.event
class CartPosition(AbstractPosition):
"""
@@ -1547,7 +1576,8 @@ class InvoiceAddress(models.Model):
order = models.OneToOneField(Order, null=True, blank=True, related_name='invoice_address', on_delete=models.CASCADE)
is_business = models.BooleanField(default=False, verbose_name=_('Business customer'))
company = models.CharField(max_length=255, blank=True, verbose_name=_('Company name'))
name = models.CharField(max_length=255, verbose_name=_('Full name'), blank=True)
name_cached = models.CharField(max_length=255, verbose_name=_('Full name'), blank=True)
name_parts = FallbackJSONField(default=dict)
street = models.TextField(verbose_name=_('Address'), blank=False)
zipcode = models.CharField(max_length=30, verbose_name=_('ZIP code'), blank=False)
city = models.CharField(max_length=255, verbose_name=_('City'), blank=False)
@@ -1565,8 +1595,25 @@ class InvoiceAddress(models.Model):
def save(self, **kwargs):
if self.order:
self.order.touch()
if self.name_parts:
self.name_cached = self.name
else:
self.name_cached = ""
super().save(**kwargs)
@property
def name(self):
if not self.name_parts:
return ""
if '_legacy' in self.name_parts:
return self.name_parts['_legacy']
if '_scheme' in self.name_parts:
scheme = PERSON_NAME_SCHEMES[self.name_parts['_scheme']]
else:
raise TypeError("Invalid name given.")
return scheme['concatenation'](self.name_parts).strip()
def cachedticket_name(instance, filename: str) -> str:
secret = get_random_string(length=16, allowed_chars=string.ascii_letters + string.digits)