class ScheduleRoomForm(I18nFormMixin, forms.Form): room = SafeModelMultipleChoiceField( label=_("Rooms"), required=False, queryset=Room.objects.none(), widget=forms.SelectMultiple(attrs={ "class": "select2", "data-placeholder": _("Rooms") }), ) def __init__(self, *args, event=None, **kwargs): self.event = event super().__init__(*args, **kwargs) self.fields["room"].queryset = self.event.rooms.all()
class ReminderFilterForm(QuestionFilterForm): questions = SafeModelMultipleChoiceField( Question.objects.none(), required=False, help_text=_("If you select no question, all questions will be used."), label=_("Questions"), ) def get_question_queryset(self): return Question.objects.filter( event=self.event, target__in=["speaker", "submission"], ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields["questions"].queryset = self.get_question_queryset()
class ReminderFilterForm(QuestionFilterForm): questions = SafeModelMultipleChoiceField( Question.objects.none(), required=False, help_text=_("If you select no question, all questions will be used."), label=_("Questions"), ) def get_question_queryset(self): # We want to exclude questions with "freeze after", the deadlines of which have passed return Question.objects.filter( event=self.event, target__in=["speaker", "submission"], ).exclude(freeze_after__lt=timezone.now()) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields["questions"].queryset = self.get_question_queryset()
class MailForm(forms.Form): recipients = forms.ChoiceField(label=_('Send email to'), widget=forms.RadioSelect, initial='orders', choices=[]) sendto = forms.MultipleChoiceField() # overridden later subject = forms.CharField(label=_("Subject")) message = forms.CharField(label=_("Message")) attachment = CachedFileField( label=_("Attachment"), required=False, ext_whitelist=(".png", ".jpg", ".gif", ".jpeg", ".pdf", ".txt", ".docx", ".gif", ".svg", ".pptx", ".ppt", ".doc", ".xlsx", ".xls", ".jfif", ".heic", ".heif", ".pages", ".bmp", ".tif", ".tiff"), help_text=_( 'Sending an attachment increases the chance of your email not arriving or being sorted into spam folders. We recommend only using PDFs ' 'of no more than 2 MB in size.'), max_size=10 * 1024 * 1024) # TODO i18n items = forms.ModelMultipleChoiceField( widget=forms.CheckboxSelectMultiple( attrs={'class': 'scrolling-multiple-choice'}), label=_('Only send to people who bought'), required=True, queryset=Item.objects.none()) filter_checkins = forms.BooleanField(label=_('Filter check-in status'), required=False) checkin_lists = SafeModelMultipleChoiceField( queryset=CheckinList.objects.none(), required=False) # overridden later not_checked_in = forms.BooleanField( label=_("Send to customers not checked in"), required=False) subevent = forms.ModelChoiceField(SubEvent.objects.none(), label=_('Only send to customers of'), required=False, empty_label=pgettext_lazy( 'subevent', 'All dates')) subevents_from = forms.SplitDateTimeField( widget=SplitDateTimePickerWidget(), label=pgettext_lazy( 'subevent', 'Only send to customers of dates starting at or after'), required=False, ) subevents_to = forms.SplitDateTimeField( widget=SplitDateTimePickerWidget(), label=pgettext_lazy('subevent', 'Only send to customers of dates starting before'), required=False, ) def clean(self): d = super().clean() if d.get('subevent') and d.get('subevents_from'): raise ValidationError( pgettext_lazy( 'subevent', 'Please either select a specific date or a date range, not both.' )) if bool(d.get('subevents_from')) != bool(d.get('subevents_to')): raise ValidationError( pgettext_lazy( 'subevent', 'If you set a date range, please set both a start and an end.' )) return d def _set_field_placeholders(self, fn, base_parameters): phs = [ '{%s}' % p for p in sorted( get_available_placeholders(self.event, base_parameters).keys()) ] ht = _('Available placeholders: {list}').format(list=', '.join(phs)) if self.fields[fn].help_text: self.fields[fn].help_text += ' ' + str(ht) else: self.fields[fn].help_text = ht self.fields[fn].validators.append(PlaceholderValidator(phs)) def __init__(self, *args, **kwargs): event = self.event = kwargs.pop('event') super().__init__(*args, **kwargs) recp_choices = [('orders', _('Everyone who created a ticket order'))] if event.settings.attendee_emails_asked: recp_choices += [ ('attendees', _('Every attendee (falling back to the order contact when no attendee email address is ' 'given)')), ('both', _('Both (all order contact addresses and all attendee email addresses)' )) ] self.fields['recipients'].choices = recp_choices self.fields['subject'] = I18nFormField( label=_('Subject'), widget=I18nTextInput, required=True, locales=event.settings.get('locales'), ) self.fields['message'] = I18nFormField( label=_('Message'), widget=I18nTextarea, required=True, locales=event.settings.get('locales'), ) self._set_field_placeholders('subject', ['event', 'order', 'position_or_address']) self._set_field_placeholders('message', ['event', 'order', 'position_or_address']) choices = [(e, l) for e, l in Order.STATUS_CHOICE if e != 'n'] choices.insert(0, ('na', _('payment pending (except unapproved)'))) choices.insert(0, ('pa', _('approval pending'))) if not event.settings.get('payment_term_expire_automatically', as_type=bool): choices.append(('overdue', _('pending with payment overdue'))) self.fields['sendto'] = forms.MultipleChoiceField( label=_("Send to customers with order status"), widget=forms.CheckboxSelectMultiple( attrs={'class': 'scrolling-multiple-choice'}), choices=choices) if not self.initial.get('sendto'): self.initial['sendto'] = ['p', 'na'] elif 'n' in self.initial['sendto']: self.initial['sendto'].append('pa') self.initial['sendto'].append('na') self.fields['items'].queryset = event.items.all() if not self.initial.get('items'): self.initial['items'] = event.items.all() self.fields['checkin_lists'].queryset = event.checkin_lists.all() self.fields['checkin_lists'].widget = Select2Multiple( attrs={ 'data-model-select2': 'generic', 'data-select2-url': reverse('control:event.orders.checkinlists.select2', kwargs={ 'event': event.slug, 'organizer': event.organizer.slug, }), 'data-placeholder': _('Send to customers checked in on list'), }) self.fields['checkin_lists'].widget.choices = self.fields[ 'checkin_lists'].choices self.fields['checkin_lists'].label = _( 'Send to customers checked in on list') if event.has_subevents: self.fields['subevent'].queryset = event.subevents.all() self.fields['subevent'].widget = Select2( attrs={ 'data-model-select2': 'event', 'data-select2-url': reverse('control:event.subevents.select2', kwargs={ 'event': event.slug, 'organizer': event.organizer.slug, }), 'data-placeholder': pgettext_lazy('subevent', 'Date') }) self.fields['subevent'].widget.choices = self.fields[ 'subevent'].choices else: del self.fields['subevent'] del self.fields['subevents_from'] del self.fields['subevents_to']
class StretchgoalsSettingsForm(I18nForm, SettingsForm): # General settings stretchgoals_start_date = forms.DateField( required=False, label=_('Start date'), widget=DatePickerWidget(), help_text=_('Will start at first sale by default.'), ) stretchgoals_end_date = forms.DateField( required=False, label=_('End date'), widget=DatePickerWidget(), help_text=_('Will end at last sale by default.'), ) stretchgoals_items = SafeModelMultipleChoiceField( queryset=Item.objects.none(), required=False, label=_('Item types'), help_text=_('Items to be included in the calculation.'), widget=forms.CheckboxSelectMultiple, ) stretchgoals_include_pending = forms.BooleanField( required=False, label=_('Include pending orders'), help_text=_( 'By default, only paid orders are included in the calculation.'), ) # Goal settings stretchgoals_new_name = I18nFormField(required=False, label=_('New goal\'s name'), widget=I18nTextInput) stretchgoals_new_total = forms.IntegerField( required=False, min_value=0, label=_('New total revenue goal')) stretchgoals_new_amount = forms.IntegerField( required=False, min_value=0, label=_('New goal\'s amount of items to be sold')) stretchgoals_new_description = I18nFormField( required=False, label=_('New goal\'s description'), widget=I18nTextarea) # Display settings stretchgoals_is_public = forms.BooleanField( required=False, label=_('Show publicly'), help_text=_('By default, the chart is only shown in the backend.'), ) stretchgoals_calculation_text = forms.BooleanField( required=False, label=_('Show public text'), help_text= _('This text will include the current state and extrapolations for all goals.' ), ) stretchgoals_chart_averages = forms.BooleanField( required=False, label=_('Generate average price graph'), help_text=_( 'This graph shows the development of the average price paid.'), ) stretchgoals_chart_totals = forms.BooleanField( required=False, label=_('Generate total revenue graph'), help_text=_('This graph shows the total revenue over time.'), ) stretchgoals_chart_itemsales = forms.BooleanField( required=False, label=_('Generate sold items graph'), help_text=_( 'This graph shows the total amount of sold items over time.'), ) stretchgoals_show_itemsales_items = forms.BooleanField( required=False, label=_('Show individual products in sold items graph'), help_text=_( 'If this option is disabled, an aggregated number will only be shown in the sold items graph.' 'Else, a per-item breakdown will be displayed'), widget=forms.CheckboxInput( attrs={ 'data-checkbox-dependency': '#id_stretchgoals_chart_itemsales' }), ) stretchgoals_min_orders = forms.IntegerField( required=False, label=_('Minimal number of orders'), help_text= _('Only show the graph if more than this many orders are taken into consideration.' ), ) stretchgoals_public_text = I18nFormField( required=False, label=_('Text shown on the public page'), help_text=_( 'Text shown on the public page. You can use the placeholder ' '{avg_now} (the current average).'), widget=I18nTextarea, ) def __init__(self, *args, **kwargs): """ Reduce possible friends_ticket_items to items of this event. """ self.event = kwargs.pop('event') super().__init__(*args, **kwargs) initial_items = (self.event.settings.get('stretchgoals_items', as_type=QuerySet) or []) if isinstance(initial_items, str) and initial_items: initial_items = self.event.items.filter( id__in=initial_items.split(',')) elif isinstance(initial_items, list): initial_items = self.event.items.filter( id__in=[i.pk for i in initial_items]) self.fields['stretchgoals_items'].queryset = Item.objects.filter( event=self.event) self.initial['stretchgoals_items'] = initial_items self.goals = get_goals(self.event) def _save_new_goal(self): goals = json.loads( self.event.settings.get('stretchgoals_goals') or "[]") new_goal = dict() for item in ['name', 'total', 'amount', 'description']: new_goal[item] = self.cleaned_data.pop( 'stretchgoals_new_{}'.format(item)) self.fields.pop('stretchgoals_new_{}'.format(item)) if new_goal['total']: goals.append(new_goal) set_goals(self.event, goals) def save(self, *args, **kwargs): self._save_new_goal() self.event.settings._h.add_type( QuerySet, lambda queryset: ','.join( [str(element.pk) for element in queryset]), lambda pk_list: Item.objects.filter(pk__in=list( filter(None, pk_list.split(','))))) super().save(*args, **kwargs)
class MailForm(forms.Form): recipients = forms.ChoiceField(label=_('Send email to'), widget=forms.RadioSelect, initial='orders', choices=[]) sendto = forms.MultipleChoiceField() # overridden later subject = forms.CharField(label=_("Subject")) message = forms.CharField(label=_("Message")) items = forms.ModelMultipleChoiceField( widget=forms.CheckboxSelectMultiple( attrs={'class': 'scrolling-multiple-choice'}), label=_('Only send to people who bought'), required=True, queryset=Item.objects.none()) filter_checkins = forms.BooleanField(label=_('Filter check-in status'), required=False) checkin_lists = SafeModelMultipleChoiceField( queryset=CheckinList.objects.none(), required=False) # overridden later not_checked_in = forms.BooleanField( label=_("Send to customers not checked in"), required=False) subevent = forms.ModelChoiceField(SubEvent.objects.none(), label=_('Only send to customers of'), required=False, empty_label=pgettext_lazy( 'subevent', 'All dates')) def _set_field_placeholders(self, fn, base_parameters): phs = [ '{%s}' % p for p in sorted( get_available_placeholders(self.event, base_parameters).keys()) ] ht = _('Available placeholders: {list}').format(list=', '.join(phs)) if self.fields[fn].help_text: self.fields[fn].help_text += ' ' + str(ht) else: self.fields[fn].help_text = ht self.fields[fn].validators.append(PlaceholderValidator(phs)) def __init__(self, *args, **kwargs): event = self.event = kwargs.pop('event') super().__init__(*args, **kwargs) recp_choices = [('orders', _('Everyone who created a ticket order'))] if event.settings.attendee_emails_asked: recp_choices += [ ('attendees', _('Every attendee (falling back to the order contact when no attendee email address is ' 'given)')), ('both', _('Both (all order contact addresses and all attendee email addresses)' )) ] self.fields['recipients'].choices = recp_choices self.fields['subject'] = I18nFormField( label=_('Subject'), widget=I18nTextInput, required=True, locales=event.settings.get('locales'), ) self.fields['message'] = I18nFormField( label=_('Message'), widget=I18nTextarea, required=True, locales=event.settings.get('locales'), ) self._set_field_placeholders('subject', ['event', 'order', 'position_or_address']) self._set_field_placeholders('message', ['event', 'order', 'position_or_address']) choices = list(Order.STATUS_CHOICE) if not event.settings.get('payment_term_expire_automatically', as_type=bool): choices.append(('overdue', _('pending with payment overdue'))) self.fields['sendto'] = forms.MultipleChoiceField( label=_("Send to customers with order status"), widget=forms.CheckboxSelectMultiple( attrs={'class': 'scrolling-multiple-choice'}), choices=choices) if not self.initial.get('sendto'): self.initial['sendto'] = ['p', 'n'] self.fields['items'].queryset = event.items.all() if not self.initial.get('items'): self.initial['items'] = event.items.all() self.fields['checkin_lists'].queryset = event.checkin_lists.all() self.fields['checkin_lists'].widget = Select2Multiple( attrs={ 'data-model-select2': 'generic', 'data-select2-url': reverse('control:event.orders.checkinlists.select2', kwargs={ 'event': event.slug, 'organizer': event.organizer.slug, }), 'data-placeholder': _('Send to customers checked in on list'), 'data-inverse-dependency': '#id_not_checked_in' }) self.fields['checkin_lists'].widget.choices = self.fields[ 'checkin_lists'].choices self.fields['checkin_lists'].label = _( 'Send to customers checked in on list') if event.has_subevents: self.fields['subevent'].queryset = event.subevents.all() self.fields['subevent'].widget = Select2( attrs={ 'data-model-select2': 'event', 'data-select2-url': reverse('control:event.subevents.select2', kwargs={ 'event': event.slug, 'organizer': event.organizer.slug, }), 'data-placeholder': pgettext_lazy('subevent', 'Date') }) self.fields['subevent'].widget.choices = self.fields[ 'subevent'].choices else: del self.fields['subevent']