mirror of
https://github.com/pretix/pretix.git
synced 2026-05-05 15:14:04 +00:00
Scheduled exports (#3033)
This commit is contained in:
@@ -40,7 +40,7 @@ from urllib.parse import urlencode, urlparse
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import MaxValueValidator, validate_email
|
||||
from django.core.validators import MaxValueValidator
|
||||
from django.db.models import Prefetch, Q, prefetch_related_objects
|
||||
from django.forms import (
|
||||
CheckboxSelectMultiple, formset_factory, inlineformset_factory,
|
||||
@@ -66,6 +66,7 @@ from pretix.base.reldate import RelativeDateField, RelativeDateTimeField
|
||||
from pretix.base.settings import (
|
||||
PERSON_NAME_SCHEMES, PERSON_NAME_TITLE_GROUPS, validate_event_settings,
|
||||
)
|
||||
from pretix.base.validators import multimail_validate
|
||||
from pretix.control.forms import (
|
||||
MultipleLanguagesWidget, SlugWidget, SplitDateTimeField,
|
||||
SplitDateTimePickerWidget,
|
||||
@@ -864,13 +865,6 @@ class InvoiceSettingsForm(SettingsForm):
|
||||
return data
|
||||
|
||||
|
||||
def multimail_validate(val):
|
||||
s = val.split(',')
|
||||
for part in s:
|
||||
validate_email(part.strip())
|
||||
return s
|
||||
|
||||
|
||||
def contains_web_channel_validate(val):
|
||||
if "web" not in val:
|
||||
raise ValidationError(_("The online shop must be selected to receive these emails."))
|
||||
|
||||
103
src/pretix/control/forms/exports.py
Normal file
103
src/pretix/control/forms/exports.py
Normal file
@@ -0,0 +1,103 @@
|
||||
#
|
||||
# This file is part of pretix (Community Edition).
|
||||
#
|
||||
# Copyright (C) 2014-2020 Raphael Michel and contributors
|
||||
# Copyright (C) 2020-2021 rami.io GmbH and contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
|
||||
# Public License as published by the Free Software Foundation in version 3 of the License.
|
||||
#
|
||||
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
|
||||
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
|
||||
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
|
||||
# this file, see <https://pretix.eu/about/en/license>.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from pytz import common_timezones
|
||||
|
||||
from pretix.base.models import ScheduledEventExport
|
||||
from pretix.base.models.exports import ScheduledOrganizerExport
|
||||
|
||||
|
||||
class ScheduledEventExportForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = ScheduledEventExport
|
||||
fields = ['mail_additional_recipients', 'mail_additional_recipients_cc', 'mail_additional_recipients_bcc',
|
||||
'mail_subject', 'mail_template', 'schedule_rrule_time', 'locale']
|
||||
widgets = {
|
||||
'mail_additional_recipients': forms.TextInput,
|
||||
'mail_additional_recipients_cc': forms.TextInput,
|
||||
'mail_additional_recipients_bcc': forms.TextInput,
|
||||
'schedule_rrule_time': forms.TimeInput(attrs={'class': 'timepickerfield', 'autocomplete': 'off'}),
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
locale_names = dict(settings.LANGUAGES)
|
||||
self.fields['locale'] = forms.ChoiceField(
|
||||
label=_('Language'),
|
||||
choices=[(a, locale_names[a]) for a in self.instance.event.settings.locales]
|
||||
)
|
||||
|
||||
def clean_mail_additional_recipients(self):
|
||||
d = self.cleaned_data['mail_additional_recipients'].replace(' ', '')
|
||||
if len(d.split(',')) > 25:
|
||||
raise ValidationError(_('Please enter less than 25 recipients.'))
|
||||
return d
|
||||
|
||||
def clean_mail_additional_recipients_cc(self):
|
||||
d = self.cleaned_data['mail_additional_recipients_cc'].replace(' ', '')
|
||||
if len(d.split(',')) > 25:
|
||||
raise ValidationError(_('Please enter less than 25 recipients.'))
|
||||
return d
|
||||
|
||||
def clean_mail_additional_recipients_bcc(self):
|
||||
d = self.cleaned_data['mail_additional_recipients_bcc'].replace(' ', '')
|
||||
if len(d.split(',')) > 25:
|
||||
raise ValidationError(_('Please enter less than 25 recipients.'))
|
||||
return d
|
||||
|
||||
|
||||
class ScheduledOrganizerExportForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = ScheduledOrganizerExport
|
||||
fields = ['mail_additional_recipients', 'mail_additional_recipients_cc', 'mail_additional_recipients_bcc',
|
||||
'mail_subject', 'mail_template', 'schedule_rrule_time', 'locale', 'timezone']
|
||||
widgets = {
|
||||
'mail_additional_recipients': forms.TextInput,
|
||||
'mail_additional_recipients_cc': forms.TextInput,
|
||||
'mail_additional_recipients_bcc': forms.TextInput,
|
||||
'schedule_rrule_time': forms.TimeInput(attrs={'class': 'timepickerfield', 'autocomplete': 'off'}),
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
locale_names = dict(settings.LANGUAGES)
|
||||
self.fields['locale'] = forms.ChoiceField(
|
||||
label=_('Language'),
|
||||
choices=[(a, locale_names[a]) for a in self.instance.organizer.settings.locales]
|
||||
)
|
||||
self.fields['timezone'] = forms.ChoiceField(
|
||||
choices=((a, a) for a in common_timezones),
|
||||
label=_("Timezone"),
|
||||
)
|
||||
|
||||
def clean_mail_additional_recipients(self):
|
||||
return self.cleaned_data['mail_additional_recipients'].replace(' ', '')
|
||||
|
||||
def clean_mail_additional_recipients_cc(self):
|
||||
return self.cleaned_data['mail_additional_recipients_cc'].replace(' ', '')
|
||||
|
||||
def clean_mail_additional_recipients_bcc(self):
|
||||
return self.cleaned_data['mail_additional_recipients_bcc'].replace(' ', '')
|
||||
@@ -227,6 +227,10 @@ class ExporterForm(forms.Form):
|
||||
elif isinstance(v, models.QuerySet):
|
||||
data[k] = [m.pk for m in v]
|
||||
|
||||
if 'all_events' in self.fields and 'events' in self.fields:
|
||||
if not data.get('all_events') and not data.get('events'):
|
||||
raise ValidationError(_('Please select some events.'))
|
||||
|
||||
return data
|
||||
|
||||
|
||||
|
||||
251
src/pretix/control/forms/rrule.py
Normal file
251
src/pretix/control/forms/rrule.py
Normal file
@@ -0,0 +1,251 @@
|
||||
#
|
||||
# This file is part of pretix (Community Edition).
|
||||
#
|
||||
# Copyright (C) 2014-2020 Raphael Michel and contributors
|
||||
# Copyright (C) 2020-2021 rami.io GmbH and contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
|
||||
# Public License as published by the Free Software Foundation in version 3 of the License.
|
||||
#
|
||||
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
|
||||
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
|
||||
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
|
||||
# this file, see <https://pretix.eu/about/en/license>.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
from datetime import timedelta
|
||||
|
||||
from dateutil.rrule import DAILY, MONTHLY, WEEKLY, YEARLY, rrule, rrulestr
|
||||
from django import forms
|
||||
from django.utils.dates import MONTHS, WEEKDAYS
|
||||
from django.utils.timezone import get_current_timezone, now
|
||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||
|
||||
|
||||
class RRuleForm(forms.Form):
|
||||
# TODO: calendar.setfirstweekday
|
||||
freq = forms.ChoiceField(
|
||||
choices=[
|
||||
('yearly', _('year(s)')),
|
||||
('monthly', _('month(s)')),
|
||||
('weekly', _('week(s)')),
|
||||
('daily', _('day(s)')),
|
||||
],
|
||||
initial='weekly'
|
||||
)
|
||||
interval = forms.IntegerField(
|
||||
label=_('Interval'),
|
||||
initial=1,
|
||||
min_value=1,
|
||||
widget=forms.NumberInput(attrs={'min': '1'})
|
||||
)
|
||||
dtstart = forms.DateField(
|
||||
label=_('Start date'),
|
||||
widget=forms.DateInput(
|
||||
attrs={
|
||||
'class': 'datepickerfield',
|
||||
'required': 'required'
|
||||
}
|
||||
),
|
||||
initial=lambda: now().astimezone(get_current_timezone()).date()
|
||||
)
|
||||
|
||||
end = forms.ChoiceField(
|
||||
choices=[
|
||||
('count', ''),
|
||||
('until', ''),
|
||||
('forever', ''),
|
||||
],
|
||||
initial='count',
|
||||
widget=forms.RadioSelect
|
||||
)
|
||||
count = forms.IntegerField(
|
||||
label=_('Number of repetitions'),
|
||||
initial=10
|
||||
)
|
||||
until = forms.DateField(
|
||||
widget=forms.DateInput(
|
||||
attrs={
|
||||
'class': 'datepickerfield',
|
||||
'required': 'required'
|
||||
}
|
||||
),
|
||||
label=_('Last date'),
|
||||
required=True,
|
||||
initial=lambda: now() + timedelta(days=30)
|
||||
)
|
||||
|
||||
yearly_bysetpos = forms.ChoiceField(
|
||||
choices=[
|
||||
('1', pgettext_lazy('rrule', 'first')),
|
||||
('2', pgettext_lazy('rrule', 'second')),
|
||||
('3', pgettext_lazy('rrule', 'third')),
|
||||
('-1', pgettext_lazy('rrule', 'last')),
|
||||
],
|
||||
required=False
|
||||
)
|
||||
yearly_same = forms.ChoiceField(
|
||||
choices=[
|
||||
('on', ''),
|
||||
('off', ''),
|
||||
],
|
||||
initial='on',
|
||||
widget=forms.RadioSelect
|
||||
)
|
||||
yearly_byweekday = forms.ChoiceField(
|
||||
choices=[
|
||||
('MO', WEEKDAYS[0]),
|
||||
('TU', WEEKDAYS[1]),
|
||||
('WE', WEEKDAYS[2]),
|
||||
('TH', WEEKDAYS[3]),
|
||||
('FR', WEEKDAYS[4]),
|
||||
('SA', WEEKDAYS[5]),
|
||||
('SU', WEEKDAYS[6]),
|
||||
('MO,TU,WE,TH,FR,SA,SU', _('Day')),
|
||||
('MO,TU,WE,TH,FR', _('Weekday')),
|
||||
('SA,SU', _('Weekend day')),
|
||||
],
|
||||
required=False
|
||||
)
|
||||
yearly_bymonth = forms.ChoiceField(
|
||||
choices=[
|
||||
(str(i), MONTHS[i]) for i in range(1, 13)
|
||||
],
|
||||
required=False
|
||||
)
|
||||
|
||||
monthly_same = forms.ChoiceField(
|
||||
choices=[
|
||||
('on', ''),
|
||||
('off', ''),
|
||||
],
|
||||
initial='on',
|
||||
widget=forms.RadioSelect
|
||||
)
|
||||
monthly_bysetpos = forms.ChoiceField(
|
||||
choices=[
|
||||
('1', pgettext_lazy('rrule', 'first')),
|
||||
('2', pgettext_lazy('rrule', 'second')),
|
||||
('3', pgettext_lazy('rrule', 'third')),
|
||||
('-1', pgettext_lazy('rrule', 'last')),
|
||||
],
|
||||
required=False
|
||||
)
|
||||
monthly_byweekday = forms.ChoiceField(
|
||||
choices=[
|
||||
('MO', WEEKDAYS[0]),
|
||||
('TU', WEEKDAYS[1]),
|
||||
('WE', WEEKDAYS[2]),
|
||||
('TH', WEEKDAYS[3]),
|
||||
('FR', WEEKDAYS[4]),
|
||||
('SA', WEEKDAYS[5]),
|
||||
('SU', WEEKDAYS[6]),
|
||||
('MO,TU,WE,TH,FR,SA,SU', _('Day')),
|
||||
('MO,TU,WE,TH,FR', _('Weekday')),
|
||||
('SA,SU', _('Weekend day')),
|
||||
],
|
||||
required=False
|
||||
)
|
||||
|
||||
weekly_byweekday = forms.MultipleChoiceField(
|
||||
choices=[
|
||||
('MO', WEEKDAYS[0]),
|
||||
('TU', WEEKDAYS[1]),
|
||||
('WE', WEEKDAYS[2]),
|
||||
('TH', WEEKDAYS[3]),
|
||||
('FR', WEEKDAYS[4]),
|
||||
('SA', WEEKDAYS[5]),
|
||||
('SU', WEEKDAYS[6]),
|
||||
],
|
||||
required=False,
|
||||
widget=forms.CheckboxSelectMultiple
|
||||
)
|
||||
|
||||
def parse_weekdays(self, value):
|
||||
m = {
|
||||
'MO': 0,
|
||||
'TU': 1,
|
||||
'WE': 2,
|
||||
'TH': 3,
|
||||
'FR': 4,
|
||||
'SA': 5,
|
||||
'SU': 6
|
||||
}
|
||||
if ',' in value:
|
||||
return [m.get(a) for a in value.split(',')]
|
||||
else:
|
||||
return m.get(value)
|
||||
|
||||
def to_rrule(self):
|
||||
rule_kwargs = {}
|
||||
rule_kwargs['dtstart'] = self.cleaned_data['dtstart']
|
||||
rule_kwargs['interval'] = self.cleaned_data['interval']
|
||||
|
||||
if self.cleaned_data['freq'] == 'yearly':
|
||||
freq = YEARLY
|
||||
if self.cleaned_data['yearly_same'] == "off":
|
||||
rule_kwargs['bysetpos'] = int(self.cleaned_data['yearly_bysetpos'])
|
||||
rule_kwargs['byweekday'] = self.parse_weekdays(self.cleaned_data['yearly_byweekday'])
|
||||
rule_kwargs['bymonth'] = int(self.cleaned_data['yearly_bymonth'])
|
||||
|
||||
elif self.cleaned_data['freq'] == 'monthly':
|
||||
freq = MONTHLY
|
||||
|
||||
if self.cleaned_data['monthly_same'] == "off":
|
||||
rule_kwargs['bysetpos'] = int(self.cleaned_data['monthly_bysetpos'])
|
||||
rule_kwargs['byweekday'] = self.parse_weekdays(self.cleaned_data['monthly_byweekday'])
|
||||
elif self.cleaned_data['freq'] == 'weekly':
|
||||
freq = WEEKLY
|
||||
|
||||
if self.cleaned_data['weekly_byweekday']:
|
||||
rule_kwargs['byweekday'] = [self.parse_weekdays(a) for a in self.cleaned_data['weekly_byweekday']]
|
||||
|
||||
elif self.cleaned_data['freq'] == 'daily':
|
||||
freq = DAILY
|
||||
|
||||
if self.cleaned_data['end'] == 'count':
|
||||
rule_kwargs['count'] = self.cleaned_data['count']
|
||||
elif self.cleaned_data['end'] == 'until':
|
||||
rule_kwargs['until'] = self.cleaned_data['until']
|
||||
return rrule(freq, **rule_kwargs)
|
||||
|
||||
@staticmethod
|
||||
def initial_from_rrule(rule: rrule):
|
||||
initial = {}
|
||||
if isinstance(rule, str):
|
||||
rule = rrulestr(rule)
|
||||
|
||||
_rule = rule._original_rule
|
||||
initial['dtstart'] = rule._dtstart
|
||||
initial['interval'] = rule._interval
|
||||
|
||||
if rule._freq == YEARLY:
|
||||
initial['freq'] = 'yearly'
|
||||
initial['yearly_bysetpos'] = _rule.get('bysetpos')
|
||||
initial['yearly_byweekday'] = _rule.get('byweekday')
|
||||
initial['yearly_bymonth'] = _rule.get('bymonth')
|
||||
elif rule._freq == MONTHLY:
|
||||
initial['freq'] = 'monthly'
|
||||
initial['monthly_bysetpos'] = _rule.get('bysetpos')
|
||||
initial['monthly_byweekday'] = _rule.get('byweekday')
|
||||
elif rule._freq == WEEKLY:
|
||||
initial['freq'] = 'weekly'
|
||||
initial['weekly_byweekday'] = _rule.get('byweekday')
|
||||
elif rule._freq == DAILY:
|
||||
initial['freq'] = 'daily'
|
||||
|
||||
if rule._count:
|
||||
initial['end'] = 'count'
|
||||
initial['count'] = rule._count
|
||||
elif rule._until:
|
||||
initial['end'] = 'until'
|
||||
initial['until'] = rule._until
|
||||
else:
|
||||
initial['end'] = 'forever'
|
||||
return initial
|
||||
@@ -19,17 +19,15 @@
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime
|
||||
from urllib.parse import urlencode
|
||||
|
||||
from django import forms
|
||||
from django.forms import formset_factory
|
||||
from django.forms.utils import ErrorDict
|
||||
from django.urls import reverse
|
||||
from django.utils.dates import MONTHS, WEEKDAYS
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from i18nfield.forms import I18nInlineFormSet
|
||||
|
||||
from pretix.base.forms import I18nModelForm
|
||||
@@ -39,6 +37,7 @@ from pretix.base.models.items import SubEventItem, SubEventItemVariation
|
||||
from pretix.base.reldate import RelativeDateTimeField, RelativeDateWrapper
|
||||
from pretix.base.templatetags.money import money_filter
|
||||
from pretix.control.forms import SplitDateTimeField, SplitDateTimePickerWidget
|
||||
from pretix.control.forms.rrule import RRuleForm
|
||||
from pretix.helpers.money import change_decimal_field
|
||||
|
||||
|
||||
@@ -440,166 +439,15 @@ class CheckinListFormSet(I18nInlineFormSet):
|
||||
return form
|
||||
|
||||
|
||||
class RRuleForm(forms.Form):
|
||||
# TODO: calendar.setfirstweekday
|
||||
class RRuleFormSetForm(RRuleForm):
|
||||
exclude = forms.BooleanField(
|
||||
label=_('Exclude these dates instead of adding them.'),
|
||||
required=False
|
||||
)
|
||||
freq = forms.ChoiceField(
|
||||
choices=[
|
||||
('yearly', _('year(s)')),
|
||||
('monthly', _('month(s)')),
|
||||
('weekly', _('week(s)')),
|
||||
('daily', _('day(s)')),
|
||||
],
|
||||
initial='weekly'
|
||||
)
|
||||
interval = forms.IntegerField(
|
||||
label=_('Interval'),
|
||||
initial=1,
|
||||
min_value=1,
|
||||
widget=forms.NumberInput(attrs={'min': '1'})
|
||||
)
|
||||
dtstart = forms.DateField(
|
||||
label=_('Start date'),
|
||||
widget=forms.DateInput(
|
||||
attrs={
|
||||
'class': 'datepickerfield',
|
||||
'required': 'required'
|
||||
}
|
||||
),
|
||||
initial=lambda: now().date()
|
||||
)
|
||||
|
||||
end = forms.ChoiceField(
|
||||
choices=[
|
||||
('count', ''),
|
||||
('until', ''),
|
||||
],
|
||||
initial='count',
|
||||
widget=forms.RadioSelect
|
||||
)
|
||||
count = forms.IntegerField(
|
||||
label=_('Number of repetitions'),
|
||||
initial=10
|
||||
)
|
||||
until = forms.DateField(
|
||||
widget=forms.DateInput(
|
||||
attrs={
|
||||
'class': 'datepickerfield',
|
||||
'required': 'required'
|
||||
}
|
||||
),
|
||||
label=_('Last date'),
|
||||
required=True,
|
||||
initial=lambda: now() + timedelta(days=30)
|
||||
)
|
||||
|
||||
yearly_bysetpos = forms.ChoiceField(
|
||||
choices=[
|
||||
('1', pgettext_lazy('rrule', 'first')),
|
||||
('2', pgettext_lazy('rrule', 'second')),
|
||||
('3', pgettext_lazy('rrule', 'third')),
|
||||
('-1', pgettext_lazy('rrule', 'last')),
|
||||
],
|
||||
required=False
|
||||
)
|
||||
yearly_same = forms.ChoiceField(
|
||||
choices=[
|
||||
('on', ''),
|
||||
('off', ''),
|
||||
],
|
||||
initial='on',
|
||||
widget=forms.RadioSelect
|
||||
)
|
||||
yearly_byweekday = forms.ChoiceField(
|
||||
choices=[
|
||||
('MO', WEEKDAYS[0]),
|
||||
('TU', WEEKDAYS[1]),
|
||||
('WE', WEEKDAYS[2]),
|
||||
('TH', WEEKDAYS[3]),
|
||||
('FR', WEEKDAYS[4]),
|
||||
('SA', WEEKDAYS[5]),
|
||||
('SU', WEEKDAYS[6]),
|
||||
('MO,TU,WE,TH,FR,SA,SU', _('Day')),
|
||||
('MO,TU,WE,TH,FR', _('Weekday')),
|
||||
('SA,SU', _('Weekend day')),
|
||||
],
|
||||
required=False
|
||||
)
|
||||
yearly_bymonth = forms.ChoiceField(
|
||||
choices=[
|
||||
(str(i), MONTHS[i]) for i in range(1, 13)
|
||||
],
|
||||
required=False
|
||||
)
|
||||
|
||||
monthly_same = forms.ChoiceField(
|
||||
choices=[
|
||||
('on', ''),
|
||||
('off', ''),
|
||||
],
|
||||
initial='on',
|
||||
widget=forms.RadioSelect
|
||||
)
|
||||
monthly_bysetpos = forms.ChoiceField(
|
||||
choices=[
|
||||
('1', pgettext_lazy('rrule', 'first')),
|
||||
('2', pgettext_lazy('rrule', 'second')),
|
||||
('3', pgettext_lazy('rrule', 'third')),
|
||||
('-1', pgettext_lazy('rrule', 'last')),
|
||||
],
|
||||
required=False
|
||||
)
|
||||
monthly_byweekday = forms.ChoiceField(
|
||||
choices=[
|
||||
('MO', WEEKDAYS[0]),
|
||||
('TU', WEEKDAYS[1]),
|
||||
('WE', WEEKDAYS[2]),
|
||||
('TH', WEEKDAYS[3]),
|
||||
('FR', WEEKDAYS[4]),
|
||||
('SA', WEEKDAYS[5]),
|
||||
('SU', WEEKDAYS[6]),
|
||||
('MO,TU,WE,TH,FR,SA,SU', _('Day')),
|
||||
('MO,TU,WE,TH,FR', _('Weekday')),
|
||||
('SA,SU', _('Weekend day')),
|
||||
],
|
||||
required=False
|
||||
)
|
||||
|
||||
weekly_byweekday = forms.MultipleChoiceField(
|
||||
choices=[
|
||||
('MO', WEEKDAYS[0]),
|
||||
('TU', WEEKDAYS[1]),
|
||||
('WE', WEEKDAYS[2]),
|
||||
('TH', WEEKDAYS[3]),
|
||||
('FR', WEEKDAYS[4]),
|
||||
('SA', WEEKDAYS[5]),
|
||||
('SU', WEEKDAYS[6]),
|
||||
],
|
||||
required=False,
|
||||
widget=forms.CheckboxSelectMultiple
|
||||
)
|
||||
|
||||
def parse_weekdays(self, value):
|
||||
m = {
|
||||
'MO': 0,
|
||||
'TU': 1,
|
||||
'WE': 2,
|
||||
'TH': 3,
|
||||
'FR': 4,
|
||||
'SA': 5,
|
||||
'SU': 6
|
||||
}
|
||||
if ',' in value:
|
||||
return [m.get(a) for a in value.split(',')]
|
||||
else:
|
||||
return m.get(value)
|
||||
|
||||
|
||||
RRuleFormSet = formset_factory(
|
||||
RRuleForm,
|
||||
RRuleFormSetForm,
|
||||
can_order=False, can_delete=True, extra=1
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user