forked from CGM_Public/pretix_original
Moved property to the inside of items
This commit is contained in:
@@ -23,41 +23,41 @@ class Migration(migrations.Migration):
|
||||
migrations.CreateModel(
|
||||
name='User',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('password', models.CharField(verbose_name='password', max_length=128)),
|
||||
('last_login', models.DateTimeField(verbose_name='last login', blank=True, null=True)),
|
||||
('is_superuser', models.BooleanField(verbose_name='superuser status', help_text='Designates that this user has all permissions without explicitly assigning them.', default=False)),
|
||||
('email', models.EmailField(verbose_name='E-mail', null=True, unique=True, db_index=True, max_length=254, blank=True)),
|
||||
('givenname', models.CharField(verbose_name='Given name', blank=True, null=True, max_length=255)),
|
||||
('familyname', models.CharField(verbose_name='Family name', blank=True, null=True, max_length=255)),
|
||||
('is_active', models.BooleanField(verbose_name='Is active', default=True)),
|
||||
('is_staff', models.BooleanField(verbose_name='Is site admin', default=False)),
|
||||
('last_login', models.DateTimeField(verbose_name='last login', null=True, blank=True)),
|
||||
('is_superuser', models.BooleanField(default=False, verbose_name='superuser status', help_text='Designates that this user has all permissions without explicitly assigning them.')),
|
||||
('email', models.EmailField(unique=True, verbose_name='E-mail', blank=True, db_index=True, max_length=254, null=True)),
|
||||
('givenname', models.CharField(verbose_name='Given name', null=True, max_length=255, blank=True)),
|
||||
('familyname', models.CharField(verbose_name='Family name', null=True, max_length=255, blank=True)),
|
||||
('is_active', models.BooleanField(default=True, verbose_name='Is active')),
|
||||
('is_staff', models.BooleanField(default=False, verbose_name='Is site admin')),
|
||||
('date_joined', models.DateTimeField(verbose_name='Date joined', auto_now_add=True)),
|
||||
('locale', models.CharField(verbose_name='Language', choices=[('en', 'English'), ('de', 'German'), ('de-informal', 'German (informal)')], default='en', max_length=50)),
|
||||
('timezone', models.CharField(verbose_name='Timezone', default='UTC', max_length=100)),
|
||||
('groups', models.ManyToManyField(verbose_name='groups', related_query_name='user', help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', to='auth.Group', blank=True)),
|
||||
('user_permissions', models.ManyToManyField(verbose_name='user permissions', related_query_name='user', help_text='Specific permissions for this user.', related_name='user_set', to='auth.Permission', blank=True)),
|
||||
('locale', models.CharField(default='en', verbose_name='Language', choices=[('en', 'English'), ('de', 'German'), ('de-informal', 'German (informal)')], max_length=50)),
|
||||
('timezone', models.CharField(default='UTC', verbose_name='Timezone', max_length=100)),
|
||||
('groups', models.ManyToManyField(related_query_name='user', verbose_name='groups', help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', blank=True, related_name='user_set', to='auth.Group')),
|
||||
('user_permissions', models.ManyToManyField(related_query_name='user', verbose_name='user permissions', help_text='Specific permissions for this user.', blank=True, related_name='user_set', to='auth.Permission')),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Users',
|
||||
'verbose_name': 'User',
|
||||
'verbose_name_plural': 'Users',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='CachedFile',
|
||||
fields=[
|
||||
('id', models.UUIDField(primary_key=True, default=uuid.uuid4, serialize=False)),
|
||||
('expires', models.DateTimeField(blank=True, null=True)),
|
||||
('date', models.DateTimeField(blank=True, null=True)),
|
||||
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
||||
('expires', models.DateTimeField(null=True, blank=True)),
|
||||
('date', models.DateTimeField(null=True, blank=True)),
|
||||
('filename', models.CharField(max_length=255)),
|
||||
('type', models.CharField(max_length=255)),
|
||||
('file', models.FileField(upload_to=pretix.base.models.cachedfile_name, blank=True, null=True)),
|
||||
('file', models.FileField(upload_to=pretix.base.models.cachedfile_name, null=True, blank=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='CachedTicket',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('provider', models.CharField(max_length=255)),
|
||||
('cachedfile', models.ForeignKey(to='pretixbase.CachedFile')),
|
||||
],
|
||||
@@ -65,50 +65,50 @@ class Migration(migrations.Migration):
|
||||
migrations.CreateModel(
|
||||
name='CartPosition',
|
||||
fields=[
|
||||
('id', models.CharField(primary_key=True, serialize=False, max_length=36)),
|
||||
('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
|
||||
('identity', models.CharField(max_length=36)),
|
||||
('version_start_date', models.DateTimeField()),
|
||||
('version_end_date', models.DateTimeField(blank=True, default=None, null=True)),
|
||||
('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
|
||||
('version_birth_date', models.DateTimeField()),
|
||||
('session', models.CharField(verbose_name='Session', blank=True, null=True, max_length=255)),
|
||||
('price', models.DecimalField(verbose_name='Price', max_digits=10, decimal_places=2)),
|
||||
('session', models.CharField(verbose_name='Session', null=True, max_length=255, blank=True)),
|
||||
('price', models.DecimalField(decimal_places=2, verbose_name='Price', max_digits=10)),
|
||||
('datetime', models.DateTimeField(verbose_name='Date', auto_now_add=True)),
|
||||
('expires', models.DateTimeField(verbose_name='Expiration date')),
|
||||
('attendee_name', models.CharField(verbose_name='Attendee name', blank=True, help_text='Empty, if this product is not an admission ticket', null=True, max_length=255)),
|
||||
('attendee_name', models.CharField(verbose_name='Attendee name', null=True, help_text='Empty, if this product is not an admission ticket', max_length=255, blank=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Cart positions',
|
||||
'verbose_name': 'Cart position',
|
||||
'verbose_name_plural': 'Cart positions',
|
||||
},
|
||||
bases=(pretix.base.models.ObjectWithAnswers, models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Event',
|
||||
fields=[
|
||||
('id', models.CharField(primary_key=True, serialize=False, max_length=36)),
|
||||
('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
|
||||
('identity', models.CharField(max_length=36)),
|
||||
('version_start_date', models.DateTimeField()),
|
||||
('version_end_date', models.DateTimeField(blank=True, default=None, null=True)),
|
||||
('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
|
||||
('version_birth_date', models.DateTimeField()),
|
||||
('name', pretix.base.i18n.I18nCharField(verbose_name='Name', max_length=200)),
|
||||
('slug', models.SlugField(verbose_name='Slug', help_text='Should be short, only contain lowercase letters and numbers, and must be unique among your events. This is being used in addresses and bank transfer references.', validators=[django.core.validators.RegexValidator(message='The slug may only contain letters, numbers, dots and dashes.', regex='^[a-zA-Z0-9.-]+$')])),
|
||||
('currency', models.CharField(verbose_name='Default currency', default='EUR', max_length=10)),
|
||||
('slug', models.SlugField(verbose_name='Slug', help_text='Should be short, only contain lowercase letters and numbers, and must be unique among your events. This is being used in addresses and bank transfer references.', validators=[django.core.validators.RegexValidator(regex='^[a-zA-Z0-9.-]+$', message='The slug may only contain letters, numbers, dots and dashes.')])),
|
||||
('currency', models.CharField(default='EUR', verbose_name='Default currency', max_length=10)),
|
||||
('date_from', models.DateTimeField(verbose_name='Event start time')),
|
||||
('date_to', models.DateTimeField(verbose_name='Event end time', blank=True, null=True)),
|
||||
('presale_end', models.DateTimeField(verbose_name='End of presale', blank=True, help_text='No products will be sold after this date.', null=True)),
|
||||
('presale_start', models.DateTimeField(verbose_name='Start of presale', blank=True, help_text='No products will be sold before this date.', null=True)),
|
||||
('plugins', models.TextField(verbose_name='Plugins', blank=True, null=True)),
|
||||
('date_to', models.DateTimeField(verbose_name='Event end time', null=True, blank=True)),
|
||||
('presale_end', models.DateTimeField(verbose_name='End of presale', help_text='No products will be sold after this date.', null=True, blank=True)),
|
||||
('presale_start', models.DateTimeField(verbose_name='Start of presale', help_text='No products will be sold before this date.', null=True, blank=True)),
|
||||
('plugins', models.TextField(verbose_name='Plugins', null=True, blank=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Events',
|
||||
'verbose_name': 'Event',
|
||||
'verbose_name_plural': 'Events',
|
||||
'ordering': ('date_from', 'name'),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='EventLock',
|
||||
fields=[
|
||||
('event', models.CharField(primary_key=True, serialize=False, max_length=36)),
|
||||
('event', models.CharField(serialize=False, max_length=36, primary_key=True)),
|
||||
('date', models.DateTimeField(auto_now=True)),
|
||||
('token', models.UUIDField(default=uuid.uuid4)),
|
||||
],
|
||||
@@ -116,31 +116,31 @@ class Migration(migrations.Migration):
|
||||
migrations.CreateModel(
|
||||
name='EventPermission',
|
||||
fields=[
|
||||
('id', models.CharField(primary_key=True, serialize=False, max_length=36)),
|
||||
('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
|
||||
('identity', models.CharField(max_length=36)),
|
||||
('version_start_date', models.DateTimeField()),
|
||||
('version_end_date', models.DateTimeField(blank=True, default=None, null=True)),
|
||||
('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
|
||||
('version_birth_date', models.DateTimeField()),
|
||||
('can_change_settings', models.BooleanField(verbose_name='Can change event settings', default=True)),
|
||||
('can_change_items', models.BooleanField(verbose_name='Can change product settings', default=True)),
|
||||
('can_view_orders', models.BooleanField(verbose_name='Can view orders', default=True)),
|
||||
('can_change_permissions', models.BooleanField(verbose_name='Can change permissions', default=True)),
|
||||
('can_change_orders', models.BooleanField(verbose_name='Can change orders', default=True)),
|
||||
('can_change_settings', models.BooleanField(default=True, verbose_name='Can change event settings')),
|
||||
('can_change_items', models.BooleanField(default=True, verbose_name='Can change product settings')),
|
||||
('can_view_orders', models.BooleanField(default=True, verbose_name='Can view orders')),
|
||||
('can_change_permissions', models.BooleanField(default=True, verbose_name='Can change permissions')),
|
||||
('can_change_orders', models.BooleanField(default=True, verbose_name='Can change orders')),
|
||||
('event', versions.models.VersionedForeignKey(to='pretixbase.Event')),
|
||||
('user', models.ForeignKey(related_name='event_perms', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Event permissions',
|
||||
'verbose_name': 'Event permission',
|
||||
'verbose_name_plural': 'Event permissions',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='EventSetting',
|
||||
fields=[
|
||||
('id', models.CharField(primary_key=True, serialize=False, max_length=36)),
|
||||
('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
|
||||
('identity', models.CharField(max_length=36)),
|
||||
('version_start_date', models.DateTimeField()),
|
||||
('version_end_date', models.DateTimeField(blank=True, default=None, null=True)),
|
||||
('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
|
||||
('version_birth_date', models.DateTimeField()),
|
||||
('key', models.CharField(max_length=255)),
|
||||
('value', models.TextField()),
|
||||
@@ -153,151 +153,151 @@ class Migration(migrations.Migration):
|
||||
migrations.CreateModel(
|
||||
name='Item',
|
||||
fields=[
|
||||
('id', models.CharField(primary_key=True, serialize=False, max_length=36)),
|
||||
('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
|
||||
('identity', models.CharField(max_length=36)),
|
||||
('version_start_date', models.DateTimeField()),
|
||||
('version_end_date', models.DateTimeField(blank=True, default=None, null=True)),
|
||||
('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
|
||||
('version_birth_date', models.DateTimeField()),
|
||||
('name', pretix.base.i18n.I18nCharField(verbose_name='Item name', max_length=255)),
|
||||
('active', models.BooleanField(verbose_name='Active', default=True)),
|
||||
('description', pretix.base.i18n.I18nTextField(verbose_name='Description', blank=True, help_text='This is shown below the product name in lists.', null=True)),
|
||||
('default_price', models.DecimalField(verbose_name='Default price', max_digits=7, null=True, decimal_places=2)),
|
||||
('tax_rate', models.DecimalField(verbose_name='Taxes included in percent', blank=True, max_digits=7, null=True, decimal_places=2)),
|
||||
('admission', models.BooleanField(verbose_name='Is an admission ticket', help_text='Whether or not buying this product allows a person to enter your event', default=False)),
|
||||
('active', models.BooleanField(default=True, verbose_name='Active')),
|
||||
('description', pretix.base.i18n.I18nTextField(verbose_name='Description', help_text='This is shown below the product name in lists.', null=True, blank=True)),
|
||||
('default_price', models.DecimalField(decimal_places=2, verbose_name='Default price', max_digits=7, null=True)),
|
||||
('tax_rate', models.DecimalField(decimal_places=2, verbose_name='Taxes included in percent', max_digits=7, null=True, blank=True)),
|
||||
('admission', models.BooleanField(default=False, verbose_name='Is an admission ticket', help_text='Whether or not buying this product allows a person to enter your event')),
|
||||
('position', models.IntegerField(default=0)),
|
||||
('picture', models.ImageField(upload_to=pretix.base.models.itempicture_upload_to, verbose_name='Product picture', blank=True, null=True)),
|
||||
('picture', models.ImageField(upload_to=pretix.base.models.itempicture_upload_to, verbose_name='Product picture', null=True, blank=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Products',
|
||||
'verbose_name': 'Product',
|
||||
'verbose_name_plural': 'Products',
|
||||
'ordering': ('category__position', 'category', 'position'),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ItemCategory',
|
||||
fields=[
|
||||
('id', models.CharField(primary_key=True, serialize=False, max_length=36)),
|
||||
('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
|
||||
('identity', models.CharField(max_length=36)),
|
||||
('version_start_date', models.DateTimeField()),
|
||||
('version_end_date', models.DateTimeField(blank=True, default=None, null=True)),
|
||||
('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
|
||||
('version_birth_date', models.DateTimeField()),
|
||||
('name', pretix.base.i18n.I18nCharField(verbose_name='Category name', max_length=255)),
|
||||
('position', models.IntegerField(default=0)),
|
||||
('event', versions.models.VersionedForeignKey(related_name='categories', to='pretixbase.Event')),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Product categories',
|
||||
'verbose_name': 'Product category',
|
||||
'verbose_name_plural': 'Product categories',
|
||||
'ordering': ('position', 'version_birth_date'),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ItemVariation',
|
||||
fields=[
|
||||
('id', models.CharField(primary_key=True, serialize=False, max_length=36)),
|
||||
('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
|
||||
('identity', models.CharField(max_length=36)),
|
||||
('version_start_date', models.DateTimeField()),
|
||||
('version_end_date', models.DateTimeField(blank=True, default=None, null=True)),
|
||||
('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
|
||||
('version_birth_date', models.DateTimeField()),
|
||||
('active', models.BooleanField(verbose_name='Active', default=True)),
|
||||
('default_price', models.DecimalField(verbose_name='Default price', blank=True, max_digits=7, null=True, decimal_places=2)),
|
||||
('active', models.BooleanField(default=True, verbose_name='Active')),
|
||||
('default_price', models.DecimalField(decimal_places=2, verbose_name='Default price', max_digits=7, null=True, blank=True)),
|
||||
('item', versions.models.VersionedForeignKey(related_name='variations', to='pretixbase.Item')),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Product variations',
|
||||
'verbose_name': 'Product variation',
|
||||
'verbose_name_plural': 'Product variations',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Order',
|
||||
fields=[
|
||||
('id', models.CharField(primary_key=True, serialize=False, max_length=36)),
|
||||
('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
|
||||
('identity', models.CharField(max_length=36)),
|
||||
('version_start_date', models.DateTimeField()),
|
||||
('version_end_date', models.DateTimeField(blank=True, default=None, null=True)),
|
||||
('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
|
||||
('version_birth_date', models.DateTimeField()),
|
||||
('code', models.CharField(verbose_name='Order code', max_length=16)),
|
||||
('status', models.CharField(verbose_name='Status', choices=[('n', 'pending'), ('p', 'paid'), ('e', 'expired'), ('c', 'cancelled'), ('r', 'refunded')], max_length=3)),
|
||||
('email', models.EmailField(verbose_name='E-mail', blank=True, null=True, max_length=254)),
|
||||
('locale', models.CharField(verbose_name='Locale', blank=True, null=True, max_length=32)),
|
||||
('secret', models.CharField(max_length=32, default=pretix.base.models.generate_secret)),
|
||||
('email', models.EmailField(verbose_name='E-mail', null=True, max_length=254, blank=True)),
|
||||
('locale', models.CharField(verbose_name='Locale', null=True, max_length=32, blank=True)),
|
||||
('secret', models.CharField(default=pretix.base.models.generate_secret, max_length=32)),
|
||||
('datetime', models.DateTimeField(verbose_name='Date')),
|
||||
('expires', models.DateTimeField(verbose_name='Expiration date')),
|
||||
('payment_date', models.DateTimeField(verbose_name='Payment date', blank=True, null=True)),
|
||||
('payment_provider', models.CharField(verbose_name='Payment provider', blank=True, null=True, max_length=255)),
|
||||
('payment_fee', models.DecimalField(verbose_name='Payment method fee', max_digits=10, default=0, decimal_places=2)),
|
||||
('payment_info', models.TextField(verbose_name='Payment information', blank=True, null=True)),
|
||||
('payment_manual', models.BooleanField(verbose_name='Payment state was manually modified', default=False)),
|
||||
('total', models.DecimalField(verbose_name='Total amount', max_digits=10, decimal_places=2)),
|
||||
('payment_date', models.DateTimeField(verbose_name='Payment date', null=True, blank=True)),
|
||||
('payment_provider', models.CharField(verbose_name='Payment provider', null=True, max_length=255, blank=True)),
|
||||
('payment_fee', models.DecimalField(decimal_places=2, default=0, verbose_name='Payment method fee', max_digits=10)),
|
||||
('payment_info', models.TextField(verbose_name='Payment information', null=True, blank=True)),
|
||||
('payment_manual', models.BooleanField(default=False, verbose_name='Payment state was manually modified')),
|
||||
('total', models.DecimalField(decimal_places=2, verbose_name='Total amount', max_digits=10)),
|
||||
('event', versions.models.VersionedForeignKey(verbose_name='Event', related_name='orders', to='pretixbase.Event')),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Orders',
|
||||
'verbose_name': 'Order',
|
||||
'verbose_name_plural': 'Orders',
|
||||
'ordering': ('-datetime',),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='OrderPosition',
|
||||
fields=[
|
||||
('id', models.CharField(primary_key=True, serialize=False, max_length=36)),
|
||||
('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
|
||||
('identity', models.CharField(max_length=36)),
|
||||
('version_start_date', models.DateTimeField()),
|
||||
('version_end_date', models.DateTimeField(blank=True, default=None, null=True)),
|
||||
('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
|
||||
('version_birth_date', models.DateTimeField()),
|
||||
('price', models.DecimalField(verbose_name='Price', max_digits=10, decimal_places=2)),
|
||||
('attendee_name', models.CharField(verbose_name='Attendee name', blank=True, help_text='Empty, if this product is not an admission ticket', null=True, max_length=255)),
|
||||
('price', models.DecimalField(decimal_places=2, verbose_name='Price', max_digits=10)),
|
||||
('attendee_name', models.CharField(verbose_name='Attendee name', null=True, help_text='Empty, if this product is not an admission ticket', max_length=255, blank=True)),
|
||||
('item', versions.models.VersionedForeignKey(verbose_name='Item', related_name='positions', to='pretixbase.Item')),
|
||||
('order', versions.models.VersionedForeignKey(verbose_name='Order', related_name='positions', to='pretixbase.Order')),
|
||||
('variation', versions.models.VersionedForeignKey(verbose_name='Variation', to='pretixbase.ItemVariation', null=True, blank=True)),
|
||||
('variation', versions.models.VersionedForeignKey(verbose_name='Variation', blank=True, null=True, to='pretixbase.ItemVariation')),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Order positions',
|
||||
'verbose_name': 'Order position',
|
||||
'verbose_name_plural': 'Order positions',
|
||||
},
|
||||
bases=(pretix.base.models.ObjectWithAnswers, models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Organizer',
|
||||
fields=[
|
||||
('id', models.CharField(primary_key=True, serialize=False, max_length=36)),
|
||||
('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
|
||||
('identity', models.CharField(max_length=36)),
|
||||
('version_start_date', models.DateTimeField()),
|
||||
('version_end_date', models.DateTimeField(blank=True, default=None, null=True)),
|
||||
('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
|
||||
('version_birth_date', models.DateTimeField()),
|
||||
('name', models.CharField(verbose_name='Name', max_length=200)),
|
||||
('slug', models.SlugField(verbose_name='Slug', help_text='Should be short, only contain lowercase letters and numbers, and must be unique among your events. This is being used in addresses and bank transfer references.', validators=[django.core.validators.RegexValidator(message='The slug may only contain letters, numbers, dots and dashes.', regex='^[a-zA-Z0-9.-]+$')])),
|
||||
('slug', models.SlugField(verbose_name='Slug', help_text='Should be short, only contain lowercase letters and numbers, and must be unique among your events. This is being used in addresses and bank transfer references.', validators=[django.core.validators.RegexValidator(regex='^[a-zA-Z0-9.-]+$', message='The slug may only contain letters, numbers, dots and dashes.')])),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Organizers',
|
||||
'verbose_name': 'Organizer',
|
||||
'verbose_name_plural': 'Organizers',
|
||||
'ordering': ('name',),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='OrganizerPermission',
|
||||
fields=[
|
||||
('id', models.CharField(primary_key=True, serialize=False, max_length=36)),
|
||||
('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
|
||||
('identity', models.CharField(max_length=36)),
|
||||
('version_start_date', models.DateTimeField()),
|
||||
('version_end_date', models.DateTimeField(blank=True, default=None, null=True)),
|
||||
('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
|
||||
('version_birth_date', models.DateTimeField()),
|
||||
('can_create_events', models.BooleanField(verbose_name='Can create events', default=True)),
|
||||
('can_create_events', models.BooleanField(default=True, verbose_name='Can create events')),
|
||||
('organizer', versions.models.VersionedForeignKey(to='pretixbase.Organizer')),
|
||||
('user', models.ForeignKey(related_name='organizer_perms', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Organizer permissions',
|
||||
'verbose_name': 'Organizer permission',
|
||||
'verbose_name_plural': 'Organizer permissions',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='OrganizerSetting',
|
||||
fields=[
|
||||
('id', models.CharField(primary_key=True, serialize=False, max_length=36)),
|
||||
('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
|
||||
('identity', models.CharField(max_length=36)),
|
||||
('version_start_date', models.DateTimeField()),
|
||||
('version_end_date', models.DateTimeField(blank=True, default=None, null=True)),
|
||||
('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
|
||||
('version_birth_date', models.DateTimeField()),
|
||||
('key', models.CharField(max_length=255)),
|
||||
('value', models.TextField()),
|
||||
@@ -310,67 +310,68 @@ class Migration(migrations.Migration):
|
||||
migrations.CreateModel(
|
||||
name='Property',
|
||||
fields=[
|
||||
('id', models.CharField(primary_key=True, serialize=False, max_length=36)),
|
||||
('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
|
||||
('identity', models.CharField(max_length=36)),
|
||||
('version_start_date', models.DateTimeField()),
|
||||
('version_end_date', models.DateTimeField(blank=True, default=None, null=True)),
|
||||
('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
|
||||
('version_birth_date', models.DateTimeField()),
|
||||
('name', pretix.base.i18n.I18nCharField(verbose_name='Property name', max_length=250)),
|
||||
('event', versions.models.VersionedForeignKey(related_name='properties', to='pretixbase.Event')),
|
||||
('item', versions.models.VersionedForeignKey(blank=True, related_name='properties', null=True, to='pretixbase.Item')),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Product properties',
|
||||
'verbose_name': 'Product property',
|
||||
'verbose_name_plural': 'Product properties',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PropertyValue',
|
||||
fields=[
|
||||
('id', models.CharField(primary_key=True, serialize=False, max_length=36)),
|
||||
('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
|
||||
('identity', models.CharField(max_length=36)),
|
||||
('version_start_date', models.DateTimeField()),
|
||||
('version_end_date', models.DateTimeField(blank=True, default=None, null=True)),
|
||||
('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
|
||||
('version_birth_date', models.DateTimeField()),
|
||||
('value', pretix.base.i18n.I18nCharField(verbose_name='Value', max_length=250)),
|
||||
('position', models.IntegerField(default=0)),
|
||||
('prop', versions.models.VersionedForeignKey(related_name='values', to='pretixbase.Property')),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Property values',
|
||||
'verbose_name': 'Property value',
|
||||
'verbose_name_plural': 'Property values',
|
||||
'ordering': ('position', 'version_birth_date'),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Question',
|
||||
fields=[
|
||||
('id', models.CharField(primary_key=True, serialize=False, max_length=36)),
|
||||
('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
|
||||
('identity', models.CharField(max_length=36)),
|
||||
('version_start_date', models.DateTimeField()),
|
||||
('version_end_date', models.DateTimeField(blank=True, default=None, null=True)),
|
||||
('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
|
||||
('version_birth_date', models.DateTimeField()),
|
||||
('question', pretix.base.i18n.I18nTextField(verbose_name='Question')),
|
||||
('type', models.CharField(verbose_name='Question type', choices=[('N', 'Number'), ('S', 'Text (one line)'), ('T', 'Multiline text'), ('B', 'Yes/No')], max_length=5)),
|
||||
('required', models.BooleanField(verbose_name='Required question', default=False)),
|
||||
('required', models.BooleanField(default=False, verbose_name='Required question')),
|
||||
('event', versions.models.VersionedForeignKey(related_name='questions', to='pretixbase.Event')),
|
||||
('items', versions.models.VersionedManyToManyField(verbose_name='Products', blank=True, help_text='This question will be asked to buyers of the selected products', related_name='questions', to='pretixbase.Item')),
|
||||
('items', versions.models.VersionedManyToManyField(to='pretixbase.Item', verbose_name='Products', help_text='This question will be asked to buyers of the selected products', related_name='questions', blank=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Questions',
|
||||
'verbose_name': 'Question',
|
||||
'verbose_name_plural': 'Questions',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='QuestionAnswer',
|
||||
fields=[
|
||||
('id', models.CharField(primary_key=True, serialize=False, max_length=36)),
|
||||
('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
|
||||
('identity', models.CharField(max_length=36)),
|
||||
('version_start_date', models.DateTimeField()),
|
||||
('version_end_date', models.DateTimeField(blank=True, default=None, null=True)),
|
||||
('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
|
||||
('version_birth_date', models.DateTimeField()),
|
||||
('answer', models.TextField()),
|
||||
('cartposition', models.ForeignKey(related_name='answers', to='pretixbase.CartPosition', null=True, blank=True)),
|
||||
('orderposition', models.ForeignKey(related_name='answers', to='pretixbase.OrderPosition', null=True, blank=True)),
|
||||
('cartposition', models.ForeignKey(blank=True, related_name='answers', null=True, to='pretixbase.CartPosition')),
|
||||
('orderposition', models.ForeignKey(blank=True, related_name='answers', null=True, to='pretixbase.OrderPosition')),
|
||||
('question', versions.models.VersionedForeignKey(related_name='answers', to='pretixbase.Question')),
|
||||
],
|
||||
options={
|
||||
@@ -380,26 +381,26 @@ class Migration(migrations.Migration):
|
||||
migrations.CreateModel(
|
||||
name='Quota',
|
||||
fields=[
|
||||
('id', models.CharField(primary_key=True, serialize=False, max_length=36)),
|
||||
('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
|
||||
('identity', models.CharField(max_length=36)),
|
||||
('version_start_date', models.DateTimeField()),
|
||||
('version_end_date', models.DateTimeField(blank=True, default=None, null=True)),
|
||||
('version_end_date', models.DateTimeField(default=None, null=True, blank=True)),
|
||||
('version_birth_date', models.DateTimeField()),
|
||||
('name', models.CharField(verbose_name='Name', max_length=200)),
|
||||
('size', models.PositiveIntegerField(verbose_name='Total capacity')),
|
||||
('event', versions.models.VersionedForeignKey(verbose_name='Event', related_name='quotas', to='pretixbase.Event')),
|
||||
('items', versions.models.VersionedManyToManyField(verbose_name='Item', blank=True, related_name='quotas', to='pretixbase.Item')),
|
||||
('variations', pretix.base.models.VariationsField(verbose_name='Variations', blank=True, related_name='quotas', to='pretixbase.ItemVariation')),
|
||||
('items', versions.models.VersionedManyToManyField(to='pretixbase.Item', verbose_name='Item', related_name='quotas', blank=True)),
|
||||
('variations', pretix.base.models.VariationsField(to='pretixbase.ItemVariation', verbose_name='Variations', related_name='quotas', blank=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Quotas',
|
||||
'verbose_name': 'Quota',
|
||||
'verbose_name_plural': 'Quotas',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='organizer',
|
||||
name='permitted',
|
||||
field=models.ManyToManyField(through='pretixbase.OrganizerPermission', related_name='organizers', to=settings.AUTH_USER_MODEL),
|
||||
field=models.ManyToManyField(related_name='organizers', to=settings.AUTH_USER_MODEL, through='pretixbase.OrganizerPermission'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='itemvariation',
|
||||
@@ -409,18 +410,13 @@ class Migration(migrations.Migration):
|
||||
migrations.AddField(
|
||||
model_name='item',
|
||||
name='category',
|
||||
field=versions.models.VersionedForeignKey(verbose_name='Category', related_name='items', to='pretixbase.ItemCategory', null=True, blank=True, on_delete=django.db.models.deletion.PROTECT),
|
||||
field=versions.models.VersionedForeignKey(verbose_name='Category', blank=True, to='pretixbase.ItemCategory', related_name='items', null=True, on_delete=django.db.models.deletion.PROTECT),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='item',
|
||||
name='event',
|
||||
field=versions.models.VersionedForeignKey(verbose_name='Event', related_name='items', to='pretixbase.Event', on_delete=django.db.models.deletion.PROTECT),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='item',
|
||||
name='properties',
|
||||
field=versions.models.VersionedManyToManyField(verbose_name='Properties', blank=True, help_text="The selected properties will be available for the user to select. After saving this field, move to the 'Variations' tab to configure the details.", related_name='items', to='pretixbase.Property'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='event',
|
||||
name='organizer',
|
||||
@@ -429,7 +425,7 @@ class Migration(migrations.Migration):
|
||||
migrations.AddField(
|
||||
model_name='event',
|
||||
name='permitted',
|
||||
field=models.ManyToManyField(through='pretixbase.EventPermission', related_name='events', to=settings.AUTH_USER_MODEL),
|
||||
field=models.ManyToManyField(related_name='events', to=settings.AUTH_USER_MODEL, through='pretixbase.EventPermission'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='cartposition',
|
||||
@@ -444,7 +440,7 @@ class Migration(migrations.Migration):
|
||||
migrations.AddField(
|
||||
model_name='cartposition',
|
||||
name='variation',
|
||||
field=versions.models.VersionedForeignKey(verbose_name='Variation', to='pretixbase.ItemVariation', null=True, blank=True),
|
||||
field=versions.models.VersionedForeignKey(verbose_name='Variation', blank=True, null=True, to='pretixbase.ItemVariation'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='cachedticket',
|
||||
|
||||
@@ -557,96 +557,6 @@ class ItemCategory(Versionable):
|
||||
return self.sortkey < other.sortkey
|
||||
|
||||
|
||||
class Property(Versionable):
|
||||
"""
|
||||
A property is a modifier which can be applied to an Item. For example
|
||||
'Size' would be a property associated with the item 'T-Shirt'.
|
||||
|
||||
:param event: The event this belongs to
|
||||
:type event: Event
|
||||
:param name: The name of this property.
|
||||
:type name: str
|
||||
"""
|
||||
|
||||
event = VersionedForeignKey(
|
||||
Event,
|
||||
related_name="properties",
|
||||
)
|
||||
name = I18nCharField(
|
||||
max_length=250,
|
||||
verbose_name=_("Property name"),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Product property")
|
||||
verbose_name_plural = _("Product properties")
|
||||
|
||||
def __str__(self):
|
||||
return str(self.name)
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
super().delete(*args, **kwargs)
|
||||
if self.event:
|
||||
self.event.get_cache().clear()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super().save(*args, **kwargs)
|
||||
if self.event:
|
||||
self.event.get_cache().clear()
|
||||
|
||||
|
||||
class PropertyValue(Versionable):
|
||||
"""
|
||||
A value of a property. If the property would be 'T-Shirt size',
|
||||
this could be 'M' or 'L'.
|
||||
|
||||
:param prop: The property this value is a valid option for.
|
||||
:type prop: Property
|
||||
:param value: The value, as a human-readable string
|
||||
:type value: str
|
||||
:param position: An integer, used for sorting
|
||||
:type position: int
|
||||
"""
|
||||
|
||||
prop = VersionedForeignKey(
|
||||
Property,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="values"
|
||||
)
|
||||
value = I18nCharField(
|
||||
max_length=250,
|
||||
verbose_name=_("Value"),
|
||||
)
|
||||
position = models.IntegerField(
|
||||
default=0
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Property value")
|
||||
verbose_name_plural = _("Property values")
|
||||
ordering = ("position", "version_birth_date")
|
||||
|
||||
def __str__(self):
|
||||
return "%s: %s" % (self.prop.name, self.value)
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
super().delete(*args, **kwargs)
|
||||
if self.prop:
|
||||
self.prop.event.get_cache().clear()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super().save(*args, **kwargs)
|
||||
if self.prop:
|
||||
self.prop.event.get_cache().clear()
|
||||
|
||||
@property
|
||||
def sortkey(self):
|
||||
return self.position, self.version_birth_date
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.sortkey < other.sortkey
|
||||
|
||||
|
||||
def itempicture_upload_to(instance, filename):
|
||||
return '%s/%s/item-%s.%s' % (
|
||||
instance.event.organizer.slug, instance.event.slug, instance.identity,
|
||||
@@ -675,7 +585,6 @@ class Item(Versionable):
|
||||
:type default_price: decimal.Decimal
|
||||
:param tax_rate: The VAT tax that is included in this item's price (in %)
|
||||
:type tax_rate: decimal.Decimal
|
||||
:param properties: A set of ``Property`` objects that should be applied to this item
|
||||
:param admission: ``True``, if this item allows persons to enter the event (as opposed to e.g. merchandise)
|
||||
:type admission: bool
|
||||
:param picture: A product picture to be shown next to the product description.
|
||||
@@ -718,17 +627,6 @@ class Item(Versionable):
|
||||
verbose_name=_("Taxes included in percent"),
|
||||
max_digits=7, decimal_places=2
|
||||
)
|
||||
properties = VersionedManyToManyField(
|
||||
Property,
|
||||
related_name='items',
|
||||
verbose_name=_("Properties"),
|
||||
blank=True,
|
||||
help_text=_(
|
||||
'The selected properties will be available for the user '
|
||||
'to select. After saving this field, move to the '
|
||||
'\'Variations\' tab to configure the details.'
|
||||
)
|
||||
)
|
||||
admission = models.BooleanField(
|
||||
verbose_name=_("Is an admission ticket"),
|
||||
help_text=_(
|
||||
@@ -945,6 +843,99 @@ class Item(Versionable):
|
||||
return price
|
||||
|
||||
|
||||
class Property(Versionable):
|
||||
"""
|
||||
A property is a modifier which can be applied to an Item. For example
|
||||
'Size' would be a property associated with the item 'T-Shirt'.
|
||||
|
||||
:param event: The event this belongs to
|
||||
:type event: Event
|
||||
:param name: The name of this property.
|
||||
:type name: str
|
||||
"""
|
||||
|
||||
event = VersionedForeignKey(
|
||||
Event,
|
||||
related_name="properties"
|
||||
)
|
||||
item = VersionedForeignKey(
|
||||
Item, related_name='properties', null=True, blank=True
|
||||
)
|
||||
name = I18nCharField(
|
||||
max_length=250,
|
||||
verbose_name=_("Property name")
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Product property")
|
||||
verbose_name_plural = _("Product properties")
|
||||
|
||||
def __str__(self):
|
||||
return str(self.name)
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
super().delete(*args, **kwargs)
|
||||
if self.event:
|
||||
self.event.get_cache().clear()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super().save(*args, **kwargs)
|
||||
if self.event:
|
||||
self.event.get_cache().clear()
|
||||
|
||||
|
||||
class PropertyValue(Versionable):
|
||||
"""
|
||||
A value of a property. If the property would be 'T-Shirt size',
|
||||
this could be 'M' or 'L'.
|
||||
|
||||
:param prop: The property this value is a valid option for.
|
||||
:type prop: Property
|
||||
:param value: The value, as a human-readable string
|
||||
:type value: str
|
||||
:param position: An integer, used for sorting
|
||||
:type position: int
|
||||
"""
|
||||
|
||||
prop = VersionedForeignKey(
|
||||
Property,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="values"
|
||||
)
|
||||
value = I18nCharField(
|
||||
max_length=250,
|
||||
verbose_name=_("Value"),
|
||||
)
|
||||
position = models.IntegerField(
|
||||
default=0
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Property value")
|
||||
verbose_name_plural = _("Property values")
|
||||
ordering = ("position", "version_birth_date")
|
||||
|
||||
def __str__(self):
|
||||
return "%s: %s" % (self.prop.name, self.value)
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
super().delete(*args, **kwargs)
|
||||
if self.prop:
|
||||
self.prop.event.get_cache().clear()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super().save(*args, **kwargs)
|
||||
if self.prop:
|
||||
self.prop.event.get_cache().clear()
|
||||
|
||||
@property
|
||||
def sortkey(self):
|
||||
return self.position, self.version_birth_date
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.sortkey < other.sortkey
|
||||
|
||||
|
||||
class ItemVariation(Versionable):
|
||||
"""
|
||||
A variation is an item combined with values for all properties
|
||||
|
||||
@@ -5,7 +5,9 @@ from itertools import product
|
||||
from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import transaction
|
||||
from django.forms import BaseInlineFormSet
|
||||
from django.forms import (
|
||||
BaseInlineFormSet, BaseModelFormSet, ModelForm, modelformset_factory,
|
||||
)
|
||||
from django.forms.widgets import flatatt
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.html import format_html
|
||||
@@ -21,6 +23,7 @@ class I18nInlineFormSet(BaseInlineFormSet):
|
||||
This is equivalent to a normal BaseInlineFormset, but cares for the special needs
|
||||
of I18nForms (see there for more information).
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.event = kwargs.pop('event', None)
|
||||
super().__init__(*args, **kwargs)
|
||||
@@ -30,6 +33,32 @@ class I18nInlineFormSet(BaseInlineFormSet):
|
||||
return super()._construct_form(i, **kwargs)
|
||||
|
||||
|
||||
class I18nFormSet(BaseModelFormSet):
|
||||
"""
|
||||
This is equivalent to a normal BaseModelFormset, but cares for the special needs
|
||||
of I18nForms (see there for more information).
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.event = kwargs.pop('event', None)
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def _construct_form(self, i, **kwargs):
|
||||
kwargs['event'] = self.event
|
||||
return super()._construct_form(i, **kwargs)
|
||||
|
||||
@property
|
||||
def empty_form(self):
|
||||
form = self.form(
|
||||
auto_id=self.auto_id,
|
||||
prefix=self.add_prefix('__prefix__'),
|
||||
empty_permitted=True,
|
||||
event=self.event
|
||||
)
|
||||
self.add_fields(form, None)
|
||||
return form
|
||||
|
||||
|
||||
class TolerantFormsetModelForm(VersionedModelForm):
|
||||
"""
|
||||
This is equivalent to a normal VersionedModelForm, but works around a problem that
|
||||
@@ -407,7 +436,6 @@ class VariationsField(forms.ModelMultipleChoiceField):
|
||||
|
||||
|
||||
class ExtFileField(forms.FileField):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
ext_whitelist = kwargs.pop("ext_whitelist")
|
||||
self.ext_whitelist = [i.lower() for i in ext_whitelist]
|
||||
@@ -422,3 +450,108 @@ class ExtFileField(forms.FileField):
|
||||
if ext not in self.ext_whitelist:
|
||||
raise forms.ValidationError(_("Filetype not allowed!"))
|
||||
return data
|
||||
|
||||
|
||||
class BaseNestedFormset(I18nFormSet):
|
||||
|
||||
def add_fields(self, form, index):
|
||||
# allow the super class to create the fields as usual
|
||||
super().add_fields(form, index)
|
||||
|
||||
form.nested = []
|
||||
for f in self.nested_formset_class:
|
||||
inner_formset = f(
|
||||
instance=form.instance,
|
||||
data=form.data if form.is_bound else None,
|
||||
prefix='%s-%s' % (form.prefix, f.get_default_prefix()),
|
||||
queryset=form.instance.values.all(),
|
||||
event=self.event
|
||||
)
|
||||
form.nested.append(inner_formset)
|
||||
|
||||
def is_valid(self):
|
||||
result = super(BaseNestedFormset, self).is_valid()
|
||||
|
||||
if self.is_bound:
|
||||
# look at any nested formsets, as well
|
||||
for form in self.forms:
|
||||
if not self._should_delete_form(form):
|
||||
for n in form.nested:
|
||||
result = result and n.is_valid()
|
||||
|
||||
return result
|
||||
|
||||
def save(self, commit=True):
|
||||
result = super(BaseNestedFormset, self).save(commit=commit)
|
||||
|
||||
for form in self.forms:
|
||||
if not self._should_delete_form(form):
|
||||
for n in form.nested:
|
||||
n.save(commit=commit)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def nestedformset_factory(model, nested_formset, form=ModelForm,
|
||||
formset=BaseNestedFormset, fk_name=None, fields=None,
|
||||
exclude=None, extra=3, can_order=False,
|
||||
can_delete=True, max_num=None,
|
||||
formfield_callback=None, widgets=None,
|
||||
validate_max=False, localized_fields=None,
|
||||
labels=None, help_texts=None, error_messages=None):
|
||||
kwargs = {
|
||||
'form': form,
|
||||
'formfield_callback': formfield_callback,
|
||||
'formset': formset,
|
||||
'extra': extra,
|
||||
'can_delete': can_delete,
|
||||
'can_order': can_order,
|
||||
'fields': fields,
|
||||
'exclude': exclude,
|
||||
'max_num': max_num,
|
||||
'widgets': widgets,
|
||||
'validate_max': validate_max,
|
||||
'localized_fields': localized_fields,
|
||||
'labels': labels,
|
||||
'help_texts': help_texts,
|
||||
'error_messages': error_messages,
|
||||
}
|
||||
|
||||
nfs_class = modelformset_factory(model, **kwargs)
|
||||
nfs_class.nested_formset_class = []
|
||||
for f in nested_formset:
|
||||
nfs_class.nested_formset_class.append(f)
|
||||
return nfs_class
|
||||
|
||||
|
||||
class NestedInnerI18nInlineFormSet(I18nFormSet):
|
||||
"""A formset for child objects related to a parent."""
|
||||
|
||||
def __init__(self, data=None, files=None, instance=None,
|
||||
save_as_new=False, prefix=None, queryset=None, **kwargs):
|
||||
if instance is None:
|
||||
self.instance = self.fk.rel.to()
|
||||
else:
|
||||
self.instance = instance
|
||||
self.save_as_new = save_as_new
|
||||
if queryset is None:
|
||||
if self.instance is not None:
|
||||
queryset = getattr(self.instance, self.fk.related_query_name()).all()
|
||||
else:
|
||||
queryset = self.model._default_manager
|
||||
if self.instance.pk is not None:
|
||||
qs = queryset
|
||||
else:
|
||||
qs = self.model._default_manager.none()
|
||||
super().__init__(data, files, prefix=prefix, queryset=qs, **kwargs)
|
||||
|
||||
@property
|
||||
def empty_form(self):
|
||||
form = self.form(
|
||||
auto_id=self.auto_id,
|
||||
prefix=self.add_prefix('__inner_prefix__'),
|
||||
empty_permitted=True,
|
||||
event=self.event
|
||||
)
|
||||
self.add_fields(form, None)
|
||||
return form
|
||||
|
||||
@@ -124,7 +124,6 @@ class ItemFormGeneral(VersionedModelForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['category'].queryset = self.instance.event.categories.current.all()
|
||||
self.fields['properties'].queryset = self.instance.event.properties.current.all()
|
||||
|
||||
class Meta:
|
||||
model = Item
|
||||
@@ -138,7 +137,6 @@ class ItemFormGeneral(VersionedModelForm):
|
||||
'picture',
|
||||
'default_price',
|
||||
'tax_rate',
|
||||
'properties',
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -79,12 +79,6 @@
|
||||
{% trans "Categories" %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'control:event.items.properties' organizer=request.event.organizer.slug event=request.event.slug %}"
|
||||
{% if "event.items.properties" in url_name %}class="active"{% endif %}>
|
||||
{% trans "Properties" %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'control:event.items.questions' organizer=request.event.organizer.slug event=request.event.slug %}"
|
||||
{% if "event.items.questions" in url_name %}class="active"{% endif %}>
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
{% extends "pretixcontrol/event/base.html" %}
|
||||
{% load i18n %}
|
||||
{% block title %}{{ item.name }} :: {% trans "Product" %}{% endblock %}
|
||||
{% block title %}{{ object.name }} :: {% trans "Product" %}{% endblock %}
|
||||
{% block content %}
|
||||
{% if item.identity %}
|
||||
<h1>{% trans "Modify product:" %} {{ item.name }}</h1>
|
||||
{% if object.identity %}
|
||||
<h1>{% trans "Modify product:" %} {{ object.name }}</h1>
|
||||
<ul class="nav nav-pills">
|
||||
<li {% if "event.item" == url_name %}class="active"{% endif %}><a href="{% url 'control:event.item' organizer=request.event.organizer.slug event=request.event.slug item=item.identity %}">{% trans "General information" %}</a></li>
|
||||
<li {% if "event.item.variations" == url_name %}class="active"{% endif %}><a href="{% url 'control:event.item.variations' organizer=request.event.organizer.slug event=request.event.slug item=item.identity %}">{% trans "Variations" %}</a></li>
|
||||
<li {% if "event.item.restrictions" == url_name %}class="active"{% endif %}><a href="{% url 'control:event.item.restrictions' organizer=request.event.organizer.slug event=request.event.slug item=item.identity %}">{% trans "Restrictions" %}</a></li>
|
||||
<li {% if "event.item" == url_name %}class="active"{% endif %}><a href="{% url 'control:event.item' organizer=request.event.organizer.slug event=request.event.slug item=object.identity %}">{% trans "General information" %}</a></li>
|
||||
<li {% if "event.item.properties" == url_name %}class="active"{% endif %}><a href="{% url 'control:event.item.properties' organizer=request.event.organizer.slug event=request.event.slug item=object.identity %}">{% trans "Properties" %}</a></li>
|
||||
<li {% if "event.item.variations" == url_name %}class="active"{% endif %}><a href="{% url 'control:event.item.variations' organizer=request.event.organizer.slug event=request.event.slug item=object.identity %}">{% trans "Variations" %}</a></li>
|
||||
<li {% if "event.item.restrictions" == url_name %}class="active"{% endif %}><a href="{% url 'control:event.item.restrictions' organizer=request.event.organizer.slug event=request.event.slug item=object.identity %}">{% trans "Restrictions" %}</a></li>
|
||||
</ul>
|
||||
{% else %}
|
||||
<h1>{% trans "Create product" %}</h1>
|
||||
@@ -15,7 +16,7 @@
|
||||
You will be able to adjust further settings in the next step.
|
||||
{% endblocktrans %}</p>
|
||||
{% endif %}
|
||||
{% if item.identity and not item.quotas.exists %}
|
||||
{% if object.identity and not object.quotas.exists %}
|
||||
<div class="alert alert-warning">
|
||||
{% blocktrans trimmed %}
|
||||
Please note, that your product will <strong>not</strong> be available for sale until you added your
|
||||
|
||||
@@ -18,10 +18,6 @@
|
||||
{% bootstrap_field form.default_price layout="horizontal" %}
|
||||
{% bootstrap_field form.tax_rate layout="horizontal" %}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{% trans "Advanced settings" %}</legend>
|
||||
{% bootstrap_field form.properties layout="horizontal" %}
|
||||
</fieldset>
|
||||
<div class="form-group submit-group">
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
{% trans "Save" %}
|
||||
|
||||
147
src/pretix/control/templates/pretixcontrol/item/properties.html
Normal file
147
src/pretix/control/templates/pretixcontrol/item/properties.html
Normal file
@@ -0,0 +1,147 @@
|
||||
{% extends "pretixcontrol/item/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
{% load formset_tags %}
|
||||
{% block inside %}
|
||||
<form class="form-horizontal branches" method="post" action="">
|
||||
{% csrf_token %}
|
||||
{% if state %}
|
||||
<div class="alert alert-{{ state.class }}">{{ state.message|safe }}</div>
|
||||
{% endif %}
|
||||
<div class="formset" data-formset data-formset-prefix="{{ formset.prefix }}">
|
||||
{{ formset.management_form }}
|
||||
<div data-formset-body>
|
||||
{% for form in formset %}
|
||||
<div class="panel panel-default" data-formset-form>
|
||||
<div class="sr-only">
|
||||
{{ form.id }}
|
||||
{% bootstrap_field form.DELETE form_group_class="" layout="inline" %}
|
||||
</div>
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">
|
||||
{% bootstrap_field form.name layout='inline' form_group_class="" %}
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
<div class="panel-body">
|
||||
<div class="nested-formset" data-formset-prefix="{{ form.nested.0.prefix }}">
|
||||
<div data-nested-formset-body>
|
||||
{{ form.nested.0.management_form }}
|
||||
{% for f in form.nested.0 %}
|
||||
<div class="form-group" data-nested-formset-form>
|
||||
{{ f.id }}
|
||||
<div class="col-sm-9">
|
||||
{% bootstrap_field f.value form_group_class="" layout="inline" %}
|
||||
</div>
|
||||
<div class="sr-only">
|
||||
{% bootstrap_field f.ORDER form_group_class="" layout="inline" %}
|
||||
{% bootstrap_field f.DELETE form_group_class="" layout="inline" %}
|
||||
</div>
|
||||
<div class="col-sm-3 text-right">
|
||||
<button type="button" class="btn btn-default"
|
||||
data-nested-formset-move-up-button>
|
||||
<i class="fa fa-arrow-up"></i></button>
|
||||
<button type="button" class="btn btn-default"
|
||||
data-nested-formset-move-down-button>
|
||||
<i class="fa fa-arrow-down"></i></button>
|
||||
<button type="button" class="btn btn-danger" data-nested-formset-delete-button>
|
||||
<i class="fa fa-trash"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<script type="form-template" data-nested-formset-empty-form>
|
||||
{% escapescript %}
|
||||
<div class="form-group" data-nested-formset-form>
|
||||
{{ form.nested.0.empty_form.id }}
|
||||
<div class="col-sm-9">
|
||||
{% bootstrap_field form.nested.0.empty_form.value form_group_class="" layout="inline" %}
|
||||
</div>
|
||||
<div class="sr-only">
|
||||
{% bootstrap_field form.nested.0.empty_form.ORDER form_group_class="" layout="inline" %}
|
||||
{% bootstrap_field form.nested.0.empty_form.DELETE form_group_class="" layout="inline" %}
|
||||
</div>
|
||||
<div class="col-sm-3 text-right">
|
||||
<button type="button" class="btn btn-default"
|
||||
data-nested-formset-move-up-button>
|
||||
<i class="fa fa-arrow-up"></i></button>
|
||||
<button type="button" class="btn btn-default"
|
||||
data-nested-formset-move-down-button>
|
||||
<i class="fa fa-arrow-down"></i></button>
|
||||
<button type="button" class="btn btn-danger" data-nested-formset-delete-button>
|
||||
<i class="fa fa-trash"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
{% endescapescript %}
|
||||
</script>
|
||||
<p style="margin-top: 10px">
|
||||
<button type="button" class="btn btn-default" data-nested-formset-add>
|
||||
<i class="fa fa-plus"></i> {% trans "Add a new value" %}</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<script type="form-template" data-formset-empty-form>
|
||||
{% escapescript %}
|
||||
<div class="panel panel-default" data-formset-form>
|
||||
<div class="sr-only">
|
||||
{{ formset.empty_form.id }}
|
||||
{% bootstrap_field formset.empty_form.DELETE form_group_class="" layout="inline" %}
|
||||
</div>
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">
|
||||
{% bootstrap_field formset.empty_form.name layout='inline' form_group_class="" %}
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
<div class="panel-body">
|
||||
<div class="nested-formset" data-formset-prefix="{{ formset.empty_form.nested.0.prefix }}">
|
||||
<div data-nested-formset-body>
|
||||
{{ formset.empty_form.nested.0.management_form }}
|
||||
</div>
|
||||
{{ '<script type="form-template" data-nested-formset-empty-form>' }}
|
||||
<div class="form-group" data-nested-formset-form>
|
||||
{{ formset.empty_form.nested.0.empty_form.id }}
|
||||
<div class="col-sm-9">
|
||||
{% bootstrap_field formset.empty_form.nested.0.empty_form.value form_group_class="" layout="inline" %}
|
||||
</div>
|
||||
<div class="sr-only">
|
||||
{% bootstrap_field formset.empty_form.nested.0.empty_form.ORDER form_group_class="" layout="inline" %}
|
||||
{% bootstrap_field formset.empty_form.nested.0.empty_form.DELETE form_group_class="" layout="inline" %}
|
||||
</div>
|
||||
<div class="col-sm-3 text-right">
|
||||
<button type="button" class="btn btn-default"
|
||||
data-nested-formset-move-up-button>
|
||||
<i class="fa fa-arrow-up"></i></button>
|
||||
<button type="button" class="btn btn-default"
|
||||
data-nested-formset-move-down-button>
|
||||
<i class="fa fa-arrow-down"></i></button>
|
||||
<button type="button" class="btn btn-danger" data-nested-formset-delete-button>
|
||||
<i class="fa fa-trash"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
{{ '</script>' }}
|
||||
|
||||
<p style="margin-top: 10px">
|
||||
<button type="button" class="btn btn-default" data-nested-formset-add>
|
||||
<i class="fa fa-plus"></i> {% trans "Add a new value" %}</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endescapescript %}
|
||||
</script>
|
||||
<p>
|
||||
<button type="button" class="btn btn-default" data-formset-add>
|
||||
<i class="fa fa-plus"></i> {% trans "Add a new property" %}</button>
|
||||
</p>
|
||||
</div>
|
||||
<div class="form-group submit-group">
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
{% trans "Save" %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -1,30 +0,0 @@
|
||||
{% extends "pretixcontrol/items/base.html" %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Product properties" %}{% endblock %}
|
||||
{% block inside %}
|
||||
<h1>{% trans "Product properties" %}</h1>
|
||||
<p>
|
||||
<a href="{% url "control:event.items.properties.add" organizer=request.event.organizer.slug event=request.event.slug %}" class="btn btn-default"><i class="fa fa-plus"></i> {% trans "Create new property" %}</a>
|
||||
</p>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans "Product properties" %}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for p in properties %}
|
||||
<tr>
|
||||
<td><strong><a href="
|
||||
{% url "control:event.items.properties.edit" organizer=request.event.organizer.slug event=request.event.slug property=p.identity %}">{{ p.name }}</a></strong></td>
|
||||
<td class="text-right"><a href="
|
||||
{% url "control:event.items.properties.delete" organizer=request.event.organizer.slug event=request.event.slug property=p.identity %}" class="btn btn-danger btn-sm"><i class="fa fa-trash"></i></a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% include "pretixcontrol/pagination.html" %}
|
||||
{% endblock %}
|
||||
@@ -1,65 +0,0 @@
|
||||
{% extends "pretixcontrol/items/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
{% load formset_tags %}
|
||||
{% block title %}{% trans "Product property" %}{% endblock %}
|
||||
{% block inside %}
|
||||
<h1>{% trans "Product property" %}</h1>
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
{% csrf_token %}
|
||||
<fieldset>
|
||||
<legend>{% trans "General information" %}</legend>
|
||||
{% bootstrap_field form.name layout="horizontal" %}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{% trans "Values" %}</legend>
|
||||
<div data-formset data-formset-prefix="{{ formset.prefix }}">
|
||||
<div data-formset-body>
|
||||
{{ formset.management_form }}
|
||||
{% for f in formset %}
|
||||
<div class="form-group" data-formset-form>
|
||||
{{ f.id }}
|
||||
<div class="col-sm-9">
|
||||
{% bootstrap_field f.value form_group_class="" layout="inline" %}
|
||||
</div>
|
||||
<div class="sr-only">
|
||||
{% bootstrap_field f.ORDER form_group_class="" layout="inline" %}
|
||||
{% bootstrap_field f.DELETE form_group_class="" layout="inline" %}
|
||||
</div>
|
||||
<div class="col-sm-3 text-right">
|
||||
<button type="button" class="btn btn-default" data-formset-move-up-button><i class="fa fa-arrow-up"></i></button>
|
||||
<button type="button" class="btn btn-default" data-formset-move-down-button><i class="fa fa-arrow-down"></i></button>
|
||||
<button type="button" class="btn btn-danger" data-formset-delete-button><i class="fa fa-trash"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<script type="form-template" data-formset-empty-form>
|
||||
{% escapescript %}
|
||||
<div class="form-group" data-formset-form>
|
||||
{{ formset.empty_form.id }}
|
||||
<div class="col-sm-9">
|
||||
{% bootstrap_field formset.empty_form.value form_group_class="" layout="inline" %}
|
||||
</div>
|
||||
<div class="sr-only">
|
||||
{% bootstrap_field formset.empty_form.ORDER form_group_class="" layout="inline" %}
|
||||
{% bootstrap_field formset.empty_form.DELETE form_group_class="" layout="inline" %}
|
||||
</div>
|
||||
<div class="col-sm-3 text-right">
|
||||
<button type="button" class="btn btn-default" data-formset-move-up-button><i class="fa fa-arrow-up"></i></button>
|
||||
<button type="button" class="btn btn-default" data-formset-move-down-button><i class="fa fa-arrow-down"></i></button>
|
||||
<button type="button" class="btn btn-danger" data-formset-delete-button><i class="fa fa-trash"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
{% endescapescript %}
|
||||
</script>
|
||||
<button type="button" class="btn btn-default" data-formset-add><i class="fa fa-plus"></i> {% trans "Add a new value" %}</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="form-group submit-group">
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
{% trans "Save" %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -1,28 +0,0 @@
|
||||
{% extends "pretixcontrol/items/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
{% block title %}{% trans "Delete product property" %}{% endblock %}
|
||||
{% block inside %}
|
||||
<h1>{% trans "Delete product property" %}</h1>
|
||||
{% if not possible %}
|
||||
<p>{% blocktrans %}You can not delete the property <strong>{{ property }}</strong> as long as the following products use it:{% endblocktrans %}</p>
|
||||
<ul>
|
||||
{% for item in dependent %}
|
||||
<li><a href="{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=item.pk %}">{{ item.name }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
{% csrf_token %}
|
||||
<p>{% blocktrans %}Are you sure you want to delete the property <strong>{{ property }}</strong>?{% endblocktrans %}</p>
|
||||
<div class="form-group submit-group">
|
||||
<a href="{% url "control:event.items.properties" organizer=request.event.organizer.slug event=request.event.slug %}" class="btn btn-default btn-cancel">
|
||||
{% trans "Cancel" %}
|
||||
</a>
|
||||
<button type="submit" class="btn btn-danger btn-save">
|
||||
{% trans "Delete" %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -32,6 +32,8 @@ urlpatterns = [
|
||||
name='event.item.variations'),
|
||||
url(r'^items/(?P<item>[0-9a-f-]+)/restrictions$', item.ItemRestrictions.as_view(),
|
||||
name='event.item.restrictions'),
|
||||
url(r'^items/(?P<item>[0-9a-f-]+)/properties$', item.ItemProperties.as_view(),
|
||||
name='event.item.properties'),
|
||||
url(r'^items/(?P<item>[0-9a-f-]+)/up$', item.item_move_up, name='event.items.up'),
|
||||
url(r'^items/(?P<item>[0-9a-f-]+)/down$', item.item_move_down, name='event.items.down'),
|
||||
url(r'^items/(?P<item>[0-9a-f-]+)/delete$', item.ItemDelete.as_view(), name='event.items.delete'),
|
||||
@@ -50,12 +52,6 @@ urlpatterns = [
|
||||
url(r'^questions/(?P<question>[0-9a-f-]+)/$', item.QuestionUpdate.as_view(),
|
||||
name='event.items.questions.edit'),
|
||||
url(r'^questions/add$', item.QuestionCreate.as_view(), name='event.items.questions.add'),
|
||||
url(r'^properties/$', item.PropertyList.as_view(), name='event.items.properties'),
|
||||
url(r'^properties/(?P<property>[0-9a-f-]+)/$', item.PropertyUpdate.as_view(),
|
||||
name='event.items.properties.edit'),
|
||||
url(r'^properties/(?P<property>[0-9a-f-]+)/delete$', item.PropertyDelete.as_view(),
|
||||
name='event.items.properties.delete'),
|
||||
url(r'^properties/add$', item.PropertyCreate.as_view(), name='event.items.properties.add'),
|
||||
url(r'^quotas/$', item.QuotaList.as_view(), name='event.items.quotas'),
|
||||
url(r'^quotas/(?P<quota>[0-9a-f-]+)/$', item.QuotaUpdate.as_view(), name='event.items.quotas.edit'),
|
||||
url(r'^quotas/(?P<quota>[0-9a-f-]+)/delete$', item.QuotaDelete.as_view(),
|
||||
|
||||
@@ -17,7 +17,10 @@ from pretix.base.models import (
|
||||
Item, ItemCategory, ItemVariation, Property, PropertyValue, Question,
|
||||
Quota,
|
||||
)
|
||||
from pretix.control.forms import I18nInlineFormSet, VariationsField
|
||||
from pretix.control.forms import (
|
||||
I18nInlineFormSet, NestedInnerI18nInlineFormSet, VariationsField,
|
||||
nestedformset_factory,
|
||||
)
|
||||
from pretix.control.forms.item import (
|
||||
CategoryForm, ItemFormGeneral, ItemVariationForm, PropertyForm,
|
||||
PropertyValueForm, QuestionForm, QuotaForm,
|
||||
@@ -219,177 +222,6 @@ def category_move_down(request, organizer, event, category):
|
||||
event=request.event.slug)
|
||||
|
||||
|
||||
class PropertyList(ListView):
|
||||
model = Property
|
||||
context_object_name = 'properties'
|
||||
paginate_by = 30
|
||||
template_name = 'pretixcontrol/items/properties.html'
|
||||
|
||||
def get_queryset(self):
|
||||
return Property.objects.current.filter(
|
||||
event=self.request.event
|
||||
)
|
||||
|
||||
|
||||
class PropertyUpdate(EventPermissionRequiredMixin, UpdateView):
|
||||
model = Property
|
||||
form_class = PropertyForm
|
||||
template_name = 'pretixcontrol/items/property.html'
|
||||
permission = 'can_change_items'
|
||||
context_object_name = 'property'
|
||||
|
||||
def get_object(self, queryset=None) -> Property:
|
||||
try:
|
||||
return self.request.event.properties.current.get(
|
||||
identity=self.kwargs['property']
|
||||
)
|
||||
except Property.DoesNotExist:
|
||||
raise Http404(_("The requested property does not exist."))
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
return reverse('control:event.items.properties.edit', kwargs={
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
'event': self.request.event.slug,
|
||||
'property': self.kwargs['property']
|
||||
})
|
||||
|
||||
def get_formset(self):
|
||||
formsetclass = inlineformset_factory(
|
||||
Property, PropertyValue,
|
||||
form=PropertyValueForm,
|
||||
formset=I18nInlineFormSet,
|
||||
can_order=True,
|
||||
extra=0,
|
||||
)
|
||||
kwargs = self.get_form_kwargs()
|
||||
kwargs['queryset'] = self.object.values.current.all()
|
||||
formset = formsetclass(**kwargs)
|
||||
return formset
|
||||
|
||||
def get_context_data(self, *args, **kwargs) -> dict:
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
context['formset'] = self.get_formset()
|
||||
return context
|
||||
|
||||
@transaction.atomic()
|
||||
def form_valid(self, form, formset):
|
||||
for f in formset.deleted_forms:
|
||||
f.instance.delete()
|
||||
f.instance.pk = None
|
||||
|
||||
for i, f in enumerate(formset.ordered_forms):
|
||||
f.save(commit=False)
|
||||
f.instance.position = i
|
||||
f.instance.save()
|
||||
|
||||
messages.success(self.request, _('Your changes have been saved.'))
|
||||
return super().form_valid(form)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
form_class = self.get_form_class()
|
||||
form = self.get_form(form_class)
|
||||
formset = self.get_formset()
|
||||
if form.is_valid() and formset.is_valid():
|
||||
return self.form_valid(form, formset)
|
||||
else:
|
||||
return self.form_invalid(form)
|
||||
|
||||
|
||||
class PropertyCreate(EventPermissionRequiredMixin, CreateView):
|
||||
model = Property
|
||||
form_class = PropertyForm
|
||||
template_name = 'pretixcontrol/items/property.html'
|
||||
permission = 'can_change_items'
|
||||
context_object_name = 'property'
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
return reverse('control:event.items.properties', kwargs={
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
'event': self.request.event.slug,
|
||||
})
|
||||
|
||||
def get_formset(self):
|
||||
formsetclass = inlineformset_factory(
|
||||
Property, PropertyValue,
|
||||
form=PropertyValueForm,
|
||||
formset=I18nInlineFormSet,
|
||||
can_order=True,
|
||||
extra=3,
|
||||
)
|
||||
formset = formsetclass(**self.get_form_kwargs())
|
||||
return formset
|
||||
|
||||
def get_context_data(self, *args, **kwargs) -> dict:
|
||||
self.object = None
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
context['formset'] = self.get_formset()
|
||||
return context
|
||||
|
||||
@transaction.atomic()
|
||||
def form_valid(self, form, formset):
|
||||
form.instance.event = self.request.event
|
||||
resp = super().form_valid(form)
|
||||
for i, f in enumerate(formset.ordered_forms):
|
||||
f.instance.position = i
|
||||
f.instance.prop = form.instance
|
||||
f.instance.save()
|
||||
messages.success(self.request, _('The new property has been created.'))
|
||||
return resp
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
form_class = self.get_form_class()
|
||||
form = self.get_form(form_class)
|
||||
formset = self.get_formset()
|
||||
if form.is_valid() and formset.is_valid():
|
||||
return self.form_valid(form, formset)
|
||||
else:
|
||||
return self.form_invalid(form)
|
||||
|
||||
|
||||
class PropertyDelete(EventPermissionRequiredMixin, DeleteView):
|
||||
model = Property
|
||||
form_class = PropertyForm
|
||||
template_name = 'pretixcontrol/items/property_delete.html'
|
||||
permission = 'can_change_items'
|
||||
context_object_name = 'property'
|
||||
|
||||
def get_context_data(self, *args, **kwargs) -> dict:
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
context['dependent'] = self.get_object().items.current.all()
|
||||
context['possible'] = self.is_allowed()
|
||||
return context
|
||||
|
||||
def is_allowed(self) -> bool:
|
||||
return self.get_object().items.current.count() == 0
|
||||
|
||||
def get_object(self, queryset=None) -> Property:
|
||||
if not hasattr(self, 'object') or not self.object:
|
||||
try:
|
||||
self.object = self.request.event.properties.current.get(
|
||||
identity=self.kwargs['property']
|
||||
)
|
||||
except Property.DoesNotExist:
|
||||
raise Http404(_("The requested property does not exist."))
|
||||
return self.object
|
||||
|
||||
def delete(self, request, *args, **kwargs):
|
||||
if self.is_allowed():
|
||||
success_url = self.get_success_url()
|
||||
self.get_object().delete()
|
||||
messages.success(request, _('The selected property has been deleted.'))
|
||||
return HttpResponseRedirect(success_url)
|
||||
else:
|
||||
messages.error(request, _('The selected property can not be deleted.'))
|
||||
return HttpResponseRedirect(self.get_success_url())
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
return reverse('control:event.items.properties', kwargs={
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
'event': self.request.event.slug,
|
||||
})
|
||||
|
||||
|
||||
class QuestionList(ListView):
|
||||
model = Question
|
||||
context_object_name = 'questions'
|
||||
@@ -676,6 +508,75 @@ class ItemUpdateGeneral(ItemDetailMixin, EventPermissionRequiredMixin, UpdateVie
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
class ItemProperties(ItemDetailMixin, EventPermissionRequiredMixin, TemplateView):
|
||||
permission = 'can_change_items'
|
||||
template_name = 'pretixcontrol/item/properties.html'
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
return reverse('control:event.item.properties', kwargs={
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
'event': self.request.event.slug,
|
||||
'item': self.get_object().identity,
|
||||
})
|
||||
|
||||
def get_inner_formset_class(self):
|
||||
formsetclass = inlineformset_factory(
|
||||
Property, PropertyValue,
|
||||
form=PropertyValueForm,
|
||||
formset=NestedInnerI18nInlineFormSet,
|
||||
can_order=True, extra=0
|
||||
)
|
||||
return formsetclass
|
||||
|
||||
def get_outer_formset(self):
|
||||
formsetclass = nestedformset_factory(
|
||||
Property, [self.get_inner_formset_class()],
|
||||
form=PropertyForm, can_order=False, can_delete=True, extra=0
|
||||
)
|
||||
formset = formsetclass(self.request.POST if self.request.method == "POST" else None,
|
||||
queryset=Property.objects.current.filter(item=self.object).prefetch_related('values'),
|
||||
event=self.request.event)
|
||||
return formset
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
self.object = self.get_object()
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['formset'] = self.get_outer_formset()
|
||||
return ctx
|
||||
|
||||
@transaction.atomic()
|
||||
def form_valid(self, formset):
|
||||
for f in formset:
|
||||
f.instance.event = self.request.event
|
||||
f.instance.item = self.get_object()
|
||||
f.instance.save()
|
||||
print(f.instance)
|
||||
|
||||
for n in f.nested:
|
||||
print(n.deleted_forms, n.ordered_forms, n.extra_forms)
|
||||
|
||||
for fn in n.deleted_forms:
|
||||
fn.instance.delete()
|
||||
fn.instance.pk = None
|
||||
|
||||
for i, fn in enumerate(n.ordered_forms + [ef for ef in n.extra_forms if ef not in n.ordered_forms]):
|
||||
fn.instance.position = i
|
||||
fn.instance.prop = f.instance
|
||||
fn.save()
|
||||
|
||||
n.save_new_objects()
|
||||
messages.success(self.request, _('Your changes have been saved.'))
|
||||
return redirect(self.get_success_url())
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
formset = self.get_outer_formset()
|
||||
if formset.is_valid():
|
||||
return self.form_valid(formset)
|
||||
else:
|
||||
return self.get(request, *args, **kwargs)
|
||||
|
||||
|
||||
class ItemVariations(ItemDetailMixin, EventPermissionRequiredMixin, TemplateView):
|
||||
permission = 'can_change_items'
|
||||
|
||||
@@ -782,7 +683,7 @@ class ItemVariations(ItemDetailMixin, EventPermissionRequiredMixin, TemplateView
|
||||
|
||||
grids.append({'row': val1, 'forms': formrow})
|
||||
|
||||
forms.append({'row': ", ".join([value.value for value in gridrow]), 'forms': grids})
|
||||
forms.append({'row': ", ".join([str(value.value) for value in gridrow]), 'forms': grids})
|
||||
|
||||
return forms, forms_flat
|
||||
|
||||
|
||||
@@ -10,29 +10,29 @@ import pretix.base.models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('pretixbase', '0001_initial'),
|
||||
('pretixbase', '__first__'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='TimeRestriction',
|
||||
fields=[
|
||||
('id', models.CharField(primary_key=True, serialize=False, max_length=36)),
|
||||
('id', models.CharField(serialize=False, max_length=36, primary_key=True)),
|
||||
('identity', models.CharField(max_length=36)),
|
||||
('version_start_date', models.DateTimeField()),
|
||||
('version_end_date', models.DateTimeField(blank=True, default=None, null=True)),
|
||||
('version_end_date', models.DateTimeField(null=True, blank=True, default=None)),
|
||||
('version_birth_date', models.DateTimeField()),
|
||||
('timeframe_from', models.DateTimeField(verbose_name='Start of time frame')),
|
||||
('timeframe_to', models.DateTimeField(verbose_name='End of time frame')),
|
||||
('price', models.DecimalField(verbose_name='Price in time frame', blank=True, max_digits=7, null=True, decimal_places=2)),
|
||||
('event', versions.models.VersionedForeignKey(verbose_name='Event', related_name='restrictions_timerestriction_timerestriction', to='pretixbase.Event')),
|
||||
('item', versions.models.VersionedForeignKey(verbose_name='Item', related_name='restrictions_timerestriction_timerestriction', to='pretixbase.Item', null=True, blank=True)),
|
||||
('variations', pretix.base.models.VariationsField(verbose_name='Variations', blank=True, related_name='restrictions_timerestriction_timerestriction', to='pretixbase.ItemVariation')),
|
||||
('price', models.DecimalField(decimal_places=2, max_digits=7, null=True, blank=True, verbose_name='Price in time frame')),
|
||||
('event', versions.models.VersionedForeignKey(verbose_name='Event', to='pretixbase.Event', related_name='restrictions_timerestriction_timerestriction')),
|
||||
('item', versions.models.VersionedForeignKey(related_name='restrictions_timerestriction_timerestriction', null=True, verbose_name='Item', to='pretixbase.Item', blank=True)),
|
||||
('variations', pretix.base.models.VariationsField(related_name='restrictions_timerestriction_timerestriction', blank=True, to='pretixbase.ItemVariation', verbose_name='Variations')),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Restrictions',
|
||||
'verbose_name': 'Restriction',
|
||||
'abstract': False,
|
||||
'verbose_name': 'Restriction',
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user