Skip to content

Conversation

@Saksham-Sirohi
Copy link
Contributor

@Saksham-Sirohi Saksham-Sirohi commented Dec 12, 2025

Fixes #1480

Summary by Sourcery

Make order-level email collection configurable and adapt checkout flow to optional or required email addresses.

New Features:

  • Add event settings to control whether an order email is asked and whether it is required.
  • Expose new order email settings in the event settings form, API serializer, and control panel UI.

Bug Fixes:

  • Ensure email fields and validation are only applied when order email collection is enabled.
  • Avoid errors when email is not collected by guarding access to email fields and cart session values.
  • Only show email in order confirmation context when it is present and not a sentinel value.

Enhancements:

  • Refactor contact form initialization to dynamically add email and repeat-email fields based on event settings.
  • Update completion checks in the questions step to respect optional order email settings.
  • Add validation to prevent enabling required order email without also asking for it.

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Dec 12, 2025

Reviewer's Guide

Makes the order-level email field configurable (asked/required), adapts checkout/contact/confirmation flows to respect these settings, and exposes the new options in settings validation, forms, API, and UI.

Sequence diagram for configurable order email flow in checkout

sequenceDiagram
    actor Buyer
    participant Browser
    participant ContactForm
    participant QuestionsStep
    participant CartSession
    participant ConfirmStep
    participant EventSettings

    Buyer->>Browser: Open checkout contact/questions step
    Browser->>QuestionsStep: GET questions_step
    QuestionsStep->>EventSettings: Read order_email_asked, order_email_required, order_email_asked_twice
    QuestionsStep->>ContactForm: Initialize(event, request, all_optional)
    ContactForm->>EventSettings: Check order_email_asked
    alt order_email_asked_true
        ContactForm->>ContactForm: Add email field (required_based_on_order_email_required)
        ContactForm->>EventSettings: Check order_email_asked_twice
        alt order_email_asked_twice_true
            ContactForm->>ContactForm: Add email_repeat field
        end
    else order_email_asked_false
        ContactForm->>ContactForm: Do_not_add_email_field
    end
    QuestionsStep-->>Browser: Render form (email field maybe present)

    Buyer->>Browser: Fill form and submit
    Browser->>QuestionsStep: POST questions_step
    QuestionsStep->>ContactForm: Validate form
    alt form_invalid
        QuestionsStep-->>Browser: Re_render_with_errors
    else form_valid
        alt email_in_cleaned_data
            QuestionsStep->>CartSession: Set email from cleaned_data
        else no_email_in_cleaned_data
            QuestionsStep->>CartSession: Remove email key
        end
        QuestionsStep-->>Browser: Redirect to next step
    end

    Buyer->>Browser: Open confirmation step
    Browser->>ConfirmStep: GET confirm_step
    ConfirmStep->>CartSession: Read contact_form_data.email
    alt email_present_and_not_none_value
        ConfirmStep-->>Browser: Show email in contact_info
    else no_email
        ConfirmStep-->>Browser: Show confirmation without email
    end
Loading

Class diagram for Event settings and checkout email handling

classDiagram
    class EventSettings {
        bool order_email_asked
        bool order_email_required
        bool order_email_asked_twice
        bool order_phone_asked
        bool order_phone_required
        bool attendee_emails_asked
        bool attendee_emails_required
    }

    class ContactForm {
        +bool all_optional
        +Event event
        +HttpRequest request
        +EmailField email
        +EmailField email_repeat
        +CharField wikimedia_username
        +__init__(args, kwargs, event, request, all_optional)
        +clean()
    }

    class QuestionsStep {
        +dict cart_session
        +HttpRequest request
        +bool all_optional
        +bool address_asked
        +contact_form()
        +post(request)
        +is_completed(request, warn)
    }

    class ConfirmStep {
        +dict cart_session
        +get_context_data(kwargs)
    }

    class SettingsValidator {
        +validate_event_settings(event, settings_dict)
    }

    EventSettings <.. ContactForm : reads
    EventSettings <.. QuestionsStep : reads
    EventSettings <.. ConfirmStep : reads
    SettingsValidator <.. EventSettings : validates
    QuestionsStep --> ContactForm : creates
    QuestionsStep --> ConfirmStep : precedes
    QuestionsStep --> cart_session : stores_email
    ConfirmStep --> cart_session : reads_email

    class EventSettingsForm {
        +bool order_email_asked
        +bool order_email_required
        +bool order_email_asked_twice
        +fields
    }

    class EventSettingsSerializer {
        +bool order_email_asked
        +bool order_email_required
        +bool order_email_asked_twice
        +fields
    }

    EventSettingsForm <.. EventSettings : configures
    EventSettingsSerializer <.. EventSettings : serializes
    SettingsValidator --> EventSettingsForm : uses_values
    SettingsValidator --> EventSettingsSerializer : uses_values
Loading

File-Level Changes

Change Details Files
Make the contact form email field conditional and respect new order email settings.
  • Remove the hard-coded email field definition from ContactForm and instantiate it dynamically in init when order_email_asked is enabled.
  • Control the email field’s required flag via order_email_required combined with the all_optional flag.
  • Re-add autofocus, help_text, and placeholder setup only when the email field is present and not rendered in an iframe.
  • Gate creation of the email_repeat field and its clean() validation logic behind both order_email_asked and order_email_asked_twice.
app/eventyay/presale/forms/checkout.py
Adjust questions step behavior to handle optional absence of the email field and store/remove email accordingly.
  • Guard email-related logic with checks that the email field exists on the contact form before disabling it based on query params.
  • On POST, set cart_session['email'] only if an email value exists in cleaned_data, otherwise remove any previously stored email.
  • In is_completed(), validate email only if order_email_asked is enabled and, when order_email_required is set, enforce presence and validity unless all_optional is true.
app/eventyay/presale/checkoutflowstep/questions_step.py
Introduce configurable settings for asking/requiring an order email and wire them through validation, API, forms, and the control UI.
  • Add order_email_asked and order_email_required settings definitions with defaults, form/serializer types, labels, help texts, and UI dependencies.
  • Validate that order_email_required cannot be enabled unless order_email_asked is also enabled in validate_event_settings.
  • Expose the new settings via EventSettingsSerializer and EventSettingsForm so they are available through the API and admin form.
  • Replace the hard-coded, always-required email checkbox block in the event settings template with a bootstrap_field rendering the combined order_email_asked_required control, and keep the existing toggle for asking email twice.
app/eventyay/base/configurations/default_setting.py
app/eventyay/base/settings.py
app/eventyay/api/serializers/event.py
app/eventyay/control/forms/event.py
app/eventyay/control/templates/pretixcontrol/event/settings.html
Ensure the confirmation step displays contact email only when present and meaningful.
  • Update confirm_step context construction to only include the E-mail contact_info entry if a non-empty email value is stored and it is not equal to EVENTYAY_EMAIL_NONE_VALUE.
app/eventyay/presale/checkoutflowstep/confirm_step.py

Assessment against linked issues

Issue Objective Addressed Explanation
#1480 On the Event Settings page, replace the existing single email checkbox with a three-option, mutually exclusive radio button selector (Do not ask / Ask, but do not require / Ask and require), with default set to "Ask and require". The PR introduces two separate boolean settings, order_email_asked and order_email_required, with defaults that map to the three logical states, and adds them to the EventSettingsForm. However, default_setting.py defines both as BooleanField (checkboxes), not a radio group, and the template only renders sform.order_email_asked_required via bootstrap_field without any corresponding field definition in the diff. There is no clear implementation of a three-option radio button group in the UI; instead, the settings behave as two checkboxes with a validation rule that order_email_required implies order_email_asked.
#1480 Implement backend logic for the three email collection states so that the order email field is hidden when not asked, shown but optional when not required, and shown and mandatory when required, while preventing invalid state combinations.
#1480 Update the presale checkout and confirmation flows so that the attendee/order form and confirmation display correctly reflect the chosen email collection behavior (including hiding email entirely when not asked).

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes and found some issues that need to be addressed.

  • In pretixcontrol/event/settings.html you render sform.order_email_asked_required, but the settings and form only define order_email_asked and order_email_required, so this should be updated to use the existing fields (or a combined virtual field) to avoid a template error.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `pretixcontrol/event/settings.html` you render `sform.order_email_asked_required`, but the settings and form only define `order_email_asked` and `order_email_required`, so this should be updated to use the existing fields (or a combined virtual field) to avoid a template error.

## Individual Comments

### Comment 1
<location> `app/eventyay/control/templates/pretixcontrol/event/settings.html:54` </location>
<code_context>
-                        </div>
-                    </div>
-                </div>
+                {% bootstrap_field sform.order_email_asked_required layout="control" %}
                 {% bootstrap_field sform.order_email_asked_twice layout="control" %}
                 {% bootstrap_field sform.include_wikimedia_username layout="control" %}
</code_context>

<issue_to_address>
**issue (bug_risk):** The template refers to `sform.order_email_asked_required`, but the settings and form only define `order_email_asked` and `order_email_required`.

`default_settings.py` and `EventSettingsForm` only define `order_email_asked` and `order_email_required`, so `sform.order_email_asked_required` will not exist and will break rendering or hide these options. Please render the two actual fields instead (e.g., separate `bootstrap_field` calls for `sform.order_email_asked` and `sform.order_email_required`).
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Member

@mariobehling mariobehling left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Please add screenshots.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR makes order-level email collection configurable by introducing two new event settings: order_email_asked (whether to ask for order email) and order_email_required (whether it's mandatory). Previously, order email was always required. This change enables events to make email optional or skip it entirely.

Key changes:

  • Added order_email_asked and order_email_required settings with corresponding validation
  • Refactored checkout form to dynamically add email fields based on settings
  • Updated checkout flow to guard email field access and handle optional email scenarios

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
app/eventyay/presale/forms/checkout.py Email and email_repeat fields now added dynamically based on event settings instead of being hardcoded
app/eventyay/presale/checkoutflowstep/questions_step.py Added guards for email field access and conditional email validation in completion checks
app/eventyay/presale/checkoutflowstep/confirm_step.py Email display now conditional on email being present and not a sentinel value
app/eventyay/control/templates/pretixcontrol/event/settings.html UI updated to show new order email settings (asked/required) or combined virtual field
app/eventyay/control/forms/event.py New settings added to EventSettingsForm auto_fields list
app/eventyay/base/settings.py Validation added to ensure order_email_required cannot be enabled without order_email_asked
app/eventyay/base/configurations/default_setting.py Defined order_email_asked and order_email_required settings with defaults, labels, and help text
app/eventyay/api/serializers/event.py Exposed new order email settings in API serializer
Comments suppressed due to low confidence (2)

app/eventyay/base/configurations/default_setting.py:215

  • The order_email_asked_twice setting should have a validation check or dependency attribute to ensure it can only be enabled when order_email_asked is also enabled. Without this, users could enable "ask twice" while disabling "ask", which would be confusing even though the code handles it safely.
    'order_email_asked_twice': {
        'default': 'False',
        'type': bool,
        'form_class': forms.BooleanField,
        'serializer_class': serializers.BooleanField,
        'form_kwargs': dict(
            label=_('Ask for the order email address twice'),
            help_text=_('Require attendees to enter their primary email address twice to help prevent errors.'),
        ),
    },

app/eventyay/presale/forms/checkout.py:71

  • When adding the email_repeat field, its required attribute should be set to match the email field's required attribute (email_required). Currently, it defaults to True (EmailField default), but should be explicitly set to email_required for consistency with the email field.
            self.fields['email_repeat'] = forms.EmailField(
                label=_('E-mail address (repeated)'),
                help_text=_('Please enter the same email address again to make sure you typed it correctly.'),
            )

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Saksham-Sirohi
Copy link
Contributor Author

Screenshot 2025-12-12 at 3 43 12 PM

@mariobehling mariobehling merged commit c6c5627 into fossasia:enext Dec 16, 2025
2 checks passed
@github-project-automation github-project-automation bot moved this from Backlog to Done in Eventyay Next Dec 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Event Settings: Replace “Email – Ask and require input” with three-option selection for email collection

3 participants