Skip to main content

Discount Scope Rules

Nota: este documento describe las reglas de alcance de un descuento (a qué parte del carrito aplica). Para tipos de descuento, combinación (cumulative) y cupones generales multi-evento, ver la guía de organizador en Descuentos y códigos.
Discounts support two explicit application scopes:
  1. Total purchase
    • Applies to registration rates, products, and custom amount fields.
    • Service fees (organizer / platform commission) are never discounted and are always calculated on the pre-discount item base (including any configured minimum, e.g. 3 EUR).
    • If the discount amount exceeds the sum of cart items, the surplus is not applied against the service fee.
  2. Rates only
    • Applies exclusively to registration rates.
    • Products, booking add-ons, and custom amount inputs remain untouched.
    • Organizer fees are not affected.
Free codes and 100% percentage discounts are the only exceptions: they intentionally leave the TPV at 0, including the service fee. Any other percentage (e.g. 25%) leaves the service fee untouched. If neither flag is selected (legacy data), the behaviour matches the previous implementation: the discount targets the sum of cart items but not organizer fees. When creating or editing a discount, the UI enforces mutual exclusivity between the two options and defaults to Total purchase for new entries.

Interaction with the unreconciled-subtotal payment guard

Order creation is protected by Order::hasUnreconciledSubtotal(), which blocks the payment step (Redsys and Stripe alike) if a non-group, non-rate-change order has exactly one order item with qty == 1 and subtotal exceeds that item’s line_amount by more than 0.02. A valid discount can only ever lower the subtotal relative to the line amount, never raise it, so an order with a correctly applied discount will never trip this guard. If a payment fails with this guard’s error while a discount is applied, the discount calculation itself is very unlikely to be the cause — check for a duplicated or stale subtotal on the order instead.