Skip to content

Conversation

@prayag78
Copy link
Contributor

@prayag78 prayag78 commented Dec 11, 2025

Description

This update ensures that when an organizer enables “Limit one ticket per user” users can no longer select more than one ticket, which makes the UI consistent with the checkout rules.

Fixes: #1471

Before

Screenshot 2025-12-12 011206 Screenshot 2025-12-12 013256

After

Screenshot 2025-12-12 013135

Checks

  • Restrict the max selectable quantity to 1 when the organizer has enabled this setting.
  • Display “Limit: 1 per user” text near the ticket type.

Summary by Sourcery

Enforce the per-user ticket limit in the presale UI and backend when the "limit one per user" setting is enabled for a product.

Bug Fixes:

  • Prevent users from selecting more than one ticket for products configured with the per-user limit, including variable products and voucher-based access.

Enhancements:

  • Display a "Limit: 1 per user" hint next to affected ticket types in product and voucher views to clarify the restriction to users.
  • Expose the per-user ticket limit flag through the widget product data to keep embedded widgets consistent with the main presale UI.

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Dec 11, 2025

Reviewer's Guide

Enforces the "limit one ticket per user" product meta in presale views and templates so that max selectable quantity is capped at 1 and the UI shows a corresponding note in product and voucher lists, including the widget API.

Sequence diagram for enforcing limit one per user in product loading

sequenceDiagram
    participant U as User
    participant V as PresaleView
    participant DB as Database
    participant GP as get_grouped_products

    U->>V: Request event page
    V->>GP: get_grouped_products(event, voucher)
    GP->>DB: Load products for event
    DB-->>GP: products
    GP->>DB: Query ProductMetaValue by product_ids and property name limit_one_per_user
    DB-->>GP: limit_one_per_user_product_ids
    loop For each product
        GP->>GP: Set product.limit_one_per_user based on id
        alt Product has no variations
            GP->>GP: Compute product.order_max
            alt product.limit_one_per_user is true
                GP->>GP: Cap product.order_max at 1
                GP->>GP: Adjust product.min_per_order to 1 if > 1
            end
        else Product has variations
            GP->>GP: Adjust product.min_per_order to 1 if limit_one_per_user and min_per_order > 1
            loop For each variation
                GP->>GP: Compute var.order_max
                alt product.limit_one_per_user is true
                    GP->>GP: Cap var.order_max at 1
                end
            end
        end
    end
    GP-->>V: Grouped products with limit_one_per_user, order_min, order_max
    V-->>U: Render templates with Limit_1_per_user text and capped quantity controls
Loading

Class diagram for Product, ProductMetaValue, and widget payload with limit_one_per_user

classDiagram
    class Event
    class Product {
        int pk
        bool has_variations
        int min_per_order
        int order_max
        bool limit_one_per_user
        tuple cached_availability
        float default_price
        float display_price
        float min_price
        float max_price
        list available_variations
    }
    class ProductVariation {
        int pk
        string description
        int order_max
        float price
    }
    class ProductMetaProperty {
        int id
        string name
        Event event
    }
    class ProductMetaValue {
        int id
        int product_id
        ProductMetaProperty property
        string value
    }
    class WidgetProductPayload {
        bool require_voucher
        int order_min
        int order_max
        bool limit_one_per_user
        object price
        float min_price
        float max_price
    }

    Event "1" -- "*" Product : has
    Product "1" -- "*" ProductVariation : has
    Product "1" -- "*" ProductMetaValue : meta_for
    ProductMetaProperty "1" -- "*" ProductMetaValue : typed_by
    Product -- WidgetProductPayload : mapped_to
Loading

File-Level Changes

Change Details Files
Compute and attach a limit_one_per_user flag to products based on ProductMetaValue and enforce it in order_min/order_max for simple products and variations.
  • Query ProductMetaValue for the current event’s products with property name 'limit_one_per_user' and build a set of product IDs.
  • Set product.limit_one_per_user for each product and, when true, cap product.order_max at 1 and normalize product.min_per_order down to 1 if it was greater than 1.
  • For non-variation products in the else-branch, also normalize product.min_per_order to 1 when limit_one_per_user is set and min_per_order exceeds 1.
  • For each variation, cap var.order_max at 1 when its product is marked limit_one_per_user.
app/eventyay/presale/views/event.py
Expose the limit_one_per_user flag to the public widget API so the frontend can honor the restriction.
  • Include limit_one_per_user in the product dict emitted by _get_products when the product has no variations.
app/eventyay/presale/views/widget.py
Display a "Limit: 1 per user" note next to affected tickets in product and voucher templates.
  • In the product list template, reposition the min_per_order note and add a conditional block that shows a styled "Limit: 1 per user" label when product.limit_one_per_user is true, in both main product list sections.
  • In the voucher template, add a conditional block under the item description that displays "Limit: 1 per user" when item.limit_one_per_user is true in both relevant sections.
app/eventyay/presale/templates/pretixpresale/event/fragment_product_list.html
app/eventyay/presale/templates/pretixpresale/event/voucher.html

Assessment against linked issues

Issue Objective Addressed Explanation
#1471 Apply the 'limit one ticket per user' setting to the public ticket selection logic so that users cannot select more than one ticket when this setting is enabled.
#1471 Restrict the maximum selectable quantity in the public tickets UI (including variations and voucher flows) to 1 when 'limit one ticket per user' is enabled.
#1471 Visually indicate the per-user limit in the public ticketing interface (e.g., by displaying text such as 'Limit: 1 per user') and support this behavior across desktop and widget/mobile views.

Possibly linked issues


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 - here's some feedback:

  • You duplicate the “Limit: 1 per user” markup in multiple templates; consider extracting this into a shared partial/macro or a small include to keep the UI text and styling consistent and easier to update.
  • In get_grouped_products, you compute and assign product.limit_one_per_user but then still check if product.pk in limit_one_per_user_product_ids when setting var.order_max; using the flag instead would simplify the logic and avoid repeated membership checks.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- You duplicate the “Limit: 1 per user” markup in multiple templates; consider extracting this into a shared partial/macro or a small include to keep the UI text and styling consistent and easier to update.
- In `get_grouped_products`, you compute and assign `product.limit_one_per_user` but then still check `if product.pk in limit_one_per_user_product_ids` when setting `var.order_max`; using the flag instead would simplify the logic and avoid repeated membership checks.

## Individual Comments

### Comment 1
<location> `app/eventyay/presale/views/event.py:366-367` </location>
<code_context>
                     max_per_order,
                 )

+                if product.pk in limit_one_per_user_product_ids:
+                    var.order_max = min(var.order_max, 1)
+
</code_context>

<issue_to_address>
**suggestion:** Use the computed `product.limit_one_per_user` flag instead of re-checking the product ID in the set.

Since `product.limit_one_per_user` is already computed in this branch, use that flag here instead of `product.pk in limit_one_per_user_product_ids`. This keeps the variation path aligned with the non-variation path and avoids two sources of truth for the same condition.

```suggestion
                if product.limit_one_per_user:
                    var.order_max = min(var.order_max, 1)
```
</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
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 ensures the "Limit one ticket per user" restriction is properly enforced in the public tickets UI. When an organizer enables this setting for a product, users can no longer select more than one ticket, making the UI consistent with backend checkout rules.

Key Changes:

  • Enforces order_max = 1 for products and variations when the limit is enabled
  • Displays "Limit: 1 per user" text in the product list and voucher views
  • Exposes the limit_one_per_user flag through the widget API

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
app/eventyay/presale/views/event.py Adds logic to query products with limit_one_per_user meta flag, enforces order_max = 1, and adjusts min_per_order to 1 if needed
app/eventyay/presale/views/widget.py Exposes limit_one_per_user flag in widget product data API
app/eventyay/presale/templates/pretixpresale/event/fragment_product_list.html Displays "Limit: 1 per user" hint for products with and without variations
app/eventyay/presale/templates/pretixpresale/event/voucher.html Displays "Limit: 1 per user" hint in voucher view for products with and without variations

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

Tickets: “Limit one ticket per user” is not reflected in the public tickets UI

2 participants