Skip to content

Quota Portal

The Quota Portal enables quota holders (sponsors, partners, officials) to manage their ticket allocations, claim tickets, and optionally delegate to sub-recipients.

Tech Stack

  • Backend: Symfony 7.x (PHP 8.2+)
  • Templates: Twig
  • Styling: SCSS imported from HNS Drupal theme (hns_theme) — same colors, fonts, forms, header, footer
  • Interactivity: Alpine.js for reactive dynamic components (multi-step forms, card selection, polling)
  • Build: Gulp (SCSS compilation, JS minification — matches Drupal theme toolchain)
  • Fonts: Hustle (headings) + Maven Pro (body) — same as HNS webshop
  • Libraries: Choices.js (dropdowns), intl-tel-input (phone), Stripe.js (payments)
  • Authentication: Same credentials as HNS mobile app (Drupal SSO → JWT)

Access Control

  • Users access portal using HNS mobile app credentials
  • Portal access granted only if user's email is associated with an active quota
  • No separate registration process required

User Capabilities

Permission Description
View Quota All quota holders can view their allocations
Claim Tickets All quota holders can claim tickets (3-step process)
Create Subquotas Only if can_create_subquotas = TRUE
Retract Subquotas Only unclaimed (ALLOCATED) subquotas
Quota Portal
├── Dashboard (My Quotas)
│   └── Quota Cards by Match
├── Quota Detail
│   ├── Allocation Summary
│   ├── Seat List
│   └── Subquota List (if permitted)
├── Claim Tickets (3-Step)
│   ├── Step 1: Select Seats
│   ├── Step 2: Ticket Holder Info
│   └── Step 3: Payment
├── Create Subquota (if permitted)
│   ├── Select Seats
│   └── Enter Recipient Details
└── My Tickets
    └── Claimed Ticket History

Screens

Dashboard (My Quotas)

Purpose: Overview of all quotas assigned to the logged-in user.

Key Components:

  • Quota Cards: One card per match with quota allocation
  • Status Summary: Quick view of allocated/claimed/sold
  • Action Buttons: Claim tickets, Open detail, Create subquota

Quota Card Layout:

┌─────────────────────────────────────────────────────────────────┐
│  🇭🇷 Croatia vs Poland                                          │
│  📅 March 15, 2026 • 20:45 • Maksimir Stadium                   │
├─────────────────────────────────────────────────────────────────┤
│  Allocated Sectors: D1, C1, B2                                  │
│  Total Seats: 50                                                │
│                                                                  │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐           │
│  │ Allocated│ │ Reserved │ │   Sold   │ │ Delegated│           │
│  │    15    │ │    5     │ │    20    │ │    10    │           │
│  │  (30%)   │ │  (10%)   │ │  (40%)   │ │  (20%)   │           │
│  └──────────┘ └──────────┘ └──────────┘ └──────────┘           │
│                                                                  │
│  Deadline: March 10, 2026 (5 days remaining)                    │
│                                                                  │
│  [Claim Tickets]  [View Details]  [Create Subquota*]            │
└─────────────────────────────────────────────────────────────────┘
* Only shown if can_create_subquotas = TRUE

Status Indicators:

  • Green Badge: Active quota
  • Yellow Badge: Past deadline (still claimable)
  • Red Badge: Cancelled by admin

Workflow Reference: Mobile Quota Claiming


Quota Detail

Purpose: Detailed view of a specific quota with seat-level visibility.

Sections:

Allocation Summary

  • Match details (teams, date, venue)
  • Allocated sectors
  • Discount information
  • Expiration date (visual reminder)
  • Transfer permission indicator (YES/NO)

Status Breakdown

┌─────────────────────────────────────────────────────────────────┐
│  Quota Status                                                    │
├─────────────────────────────────────────────────────────────────┤
│  ████████████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░           │
│                                                                  │
│  ■ Allocated: 15 seats (available for claiming)                 │
│  ■ Reserved: 5 seats (info filled, pending payment)             │
│  ■ Sold: 20 seats (completed)                                   │
│  ■ Delegated: 10 seats (assigned to subquotas)                  │
└─────────────────────────────────────────────────────────────────┘

Seat List Table

Sector Row Seat Status Assigned To Claimed Date
D1 5 1 Sold Ivan H. 2026-01-15
D1 5 2 Sold Marija K. 2026-01-15
D1 5 3 Reserved Pending... -
D1 5 4 Allocated - -
D1 5 5 Delegated → Subquota #123 -

Subquota List (if permitted)

Recipient Email Seats Status Created Actions
Ana Novak ana@corp.hr 5 SOLD Jan 10 View
Pero Babic pero@corp.hr 3 ALLOCATED Jan 12 View, Retract
Ivana Matic ivana@corp.hr 2 RESERVED Jan 14 View

Subquota Status Badges:

  • Yellow (ALLOCATED): Not yet started claiming
  • Blue (RESERVED): Info filled, pending payment
  • Green (SOLD): Completed
  • Red (Cancelled): Retracted or admin cancelled

Workflow Reference: Quota Holder Web Delegation


Claim Tickets (3-Step Process)

Purpose: Claim allocated tickets through a guided 3-step flow.

Step 1: Select Seats

For Numbered Matches: - Stadium map showing allocated seats - Click seats to select/deselect - Selected seats highlighted - Selection summary displayed

For Non-Numbered Matches: - Quantity selector only - No seat map shown

Components: - Stadium visualization (sector view) - Seat selection checkboxes - Selection counter - Continue button

Layout:

┌─────────────────────────────────────────────────────────────────┐
│  Step 1 of 3: Select Seats                                      │
│  ━━━━━━━━━━━━●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━                   │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Sector D1 - Your Allocated Seats                               │
│                                                                  │
│     1   2   3   4   5   6   7   8   9   10                      │
│  ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐                     │
│  │ ✓ │ ✓ │ ● │ ● │ ● │ ○ │ ○ │ ○ │ ○ │ ○ │  Row 5             │
│  └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘                     │
│                                                                  │
│  Legend: ✓ Selected  ● Available  ○ Sold/Delegated             │
│                                                                  │
│  Selected: 2 seats (Row 5: Seats 1-2)                           │
│                                                                  │
│  [← Back to Quota]                    [Continue to Step 2 →]    │
└─────────────────────────────────────────────────────────────────┘

Step 2: Enter Ticket Holder Information

Important Notice (displayed at top):

"Email Required: Each ticket will be delivered to the HNS mobile app linked to the email address you provide. All tickets with the same email must enter the stadium together on the same device."

Per-Ticket Form:

Field Type Validation
Full Name Text Required
Date of Birth Date Required
Nationality Dropdown Required
OIB Text Required for Croatians, checksum validated
Passport Text Required for foreigners
Email Email Required, format validated
Phone Text Optional

Features: - Select from saved profiles dropdown - Add new profile option - Real-time validation - Blacklist check (silent) - Progress indicator (e.g., "2 of 5 tickets completed")

Identity Uniqueness (per match): - Each ticket holder must have a unique OIB (Croatians) or passport number (foreigners) per match - The same OIB/passport cannot appear on multiple tickets for the same match, even across different quotas - Validated both client-side (within claim form) and server-side (across all tickets for the match)

Minor Restriction: - If DOB indicates under 18, email field disabled - Message: "Tickets for minors cannot be assigned to a separate email. Minor must enter with accompanying adult."

Layout:

┌─────────────────────────────────────────────────────────────────┐
│  Step 2 of 3: Ticket Holder Information                         │
│  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━●━━━━━━━━━━━━━━━━                  │
├─────────────────────────────────────────────────────────────────┤
│  ℹ️ Email Required: Each ticket will be delivered to the HNS    │
│     mobile app linked to the email address you provide.         │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Ticket 1 of 2 - Row 5, Seat 1                                  │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │ [Select from saved profiles ▼] or enter new details     │    │
│  │                                                          │    │
│  │ Full Name:     [________________________]               │    │
│  │ Date of Birth: [__/__/____]                             │    │
│  │ Nationality:   [Croatia          ▼]                     │    │
│  │ OIB:           [___________] ✓                          │    │
│  │ Email:         [____________________@____]              │    │
│  │ Phone:         [__________________] (optional)          │    │
│  │                                                          │    │
│  │ [ ] Save as new profile                                 │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                  │
│  Progress: ████░░░░░░ 1 of 2 completed                          │
│                                                                  │
│  [← Back to Seat Selection]          [Continue to Payment →]    │
└─────────────────────────────────────────────────────────────────┘

Workflow Reference: Mobile Quota Claiming - Step 5

Step 3: Payment

If Payment Required: - Order summary with itemized prices - Applied discount display - Payment method selection - Redirect to payment gateway

If Free Quota (discount_code = GR): - Payment step skipped - Direct confirmation

Order Summary:

┌─────────────────────────────────────────────────────────────────┐
│  Step 3 of 3: Payment                                           │
│  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━●                   │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Order Summary                                                   │
│  ─────────────────────────────────────────────                  │
│  2x Tickets - Sector D1, Row 5                                  │
│                                                                  │
│  Original Price:     2 × €50.00 = €100.00                       │
│  Sponsor Discount:              - €100.00 (100%)                │
│  ─────────────────────────────────────────────                  │
│  Total:                           €0.00                         │
│                                                                  │
│  [Complete Claim]                                               │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Post-Payment: - Tickets delivered to recipients' HNS mobile apps - Confirmation email sent - Redirect to confirmation screen


Create Subquota

Purpose: Delegate part of quota allocation to another recipient.

Prerequisite: can_create_subquotas = TRUE

Step 1: Select Seats for Subquota

Components: - Seat map showing available seats - Multi-select capability - Selection summary

Seat States: - Selectable: Available for delegation - Grayed: Already claimed (SOLD) - Different color: Already delegated to subquota

Step 2: Enter Recipient Details

Field Type Required
Recipient Email Email Yes
Recipient Name Text Yes
Internal Note Text No

Validation: - Email format check - No duplicate detection (same email can have multiple subquotas)

Create Button: Creates subquota and sends email invitation

Layout:

┌─────────────────────────────────────────────────────────────────┐
│  Create Subquota                                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Step 1: Select Seats                                           │
│                                                                  │
│  Sector D1 - Available Seats                                    │
│     1   2   3   4   5   6   7   8   9   10                      │
│  ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐                     │
│  │ ✓ │ ✓ │ ✓ │ ● │ ● │ ░ │ ░ │ ░ │ ░ │ ░ │  Row 5             │
│  └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘                     │
│                                                                  │
│  Legend: ✓ Selected  ● Available  ░ Sold/Delegated             │
│                                                                  │
│  Selected for subquota: 3 seats (Row 5: Seats 1-3)             │
│                                                                  │
│  ─────────────────────────────────────────────                  │
│                                                                  │
│  Step 2: Recipient Details                                      │
│                                                                  │
│  Recipient Email: [____________________@____] *                 │
│  Recipient Name:  [________________________] *                  │
│  Internal Note:   [________________________]                    │
│                                                                  │
│  * Required fields                                              │
│                                                                  │
│  [Cancel]                              [Create Subquota]        │
└─────────────────────────────────────────────────────────────────┘

Post-Creation: - Subquota created with status "ALLOCATED" - Email sent to recipient with claiming instructions - Push notification if recipient has HNS app - Parent's dashboard updated

Workflow Reference: Quota Holder Web Delegation


Retract Subquota

Purpose: Cancel an unclaimed subquota and return seats.

Conditions: - Subquota status must be "ALLOCATED" (not claimed yet) - Cannot retract RESERVED or SOLD subquotas

Process: 1. Click "Retract" button on subquota row 2. Confirmation dialog: "Are you sure? [Name] will be notified." 3. Confirm retraction 4. Seats returned to parent quota 5. Cancellation email sent to sub-recipient

Error Message (if claimed):

"Cannot retract subquota. Sub-recipient has already started or completed claiming process."


My Tickets

Purpose: View tickets that the quota holder has claimed for themselves.

Table Columns:

Column Description
Match Event name and date
Seat Sector, row, seat number
Ticket Holder Name on ticket
Status SOLD, Transferred, Refunded
Actions View ticket

Note: This shows tickets where the quota holder is the ticket holder (buyer), not tickets delegated to others.


Quota Status Definitions

Status Description User Actions
ALLOCATED Seats assigned, not claimed Start claiming
RESERVED Info filled, pending payment Complete payment
SOLD Payment complete, tickets issued View in mobile app
Delegated Assigned to subquota View subquota status
Cancelled Admin cancelled None

Transfer Permission

Tickets claimed from quotas inherit the quota's transfer setting:

Setting Behavior
Transfer = YES Ticket holder sees "Reassign Ticket" in app, no time restrictions
Transfer = NO Standard rules: contact support, 48-hour deadline

This is typically set to YES only for players and special VIPs.


Important Notes

Expiration Date Behavior

  • The expiration date is a visual reminder only
  • There is no automatic expiry
  • Quota holders can claim after deadline until admin manually cancels
  • Past-deadline quotas show "Past Deadline" warning but remain functional

Subquota Refund Behavior

When a ticket claimed from a subquota is refunded:

  • Refund goes to the payer
  • Ticket marked as "Cancelled (Refunded)"
  • Seat does NOT return to subquota owner
  • Seat is treated as used, not available for re-claiming
  • Admin must manually create new allocation if needed

Error Messages

Scenario Message
Blacklist rejection "HNS is prevented from issuing a ticket to this person pursuant to applicable law. For all information regarding this restriction, please contact MUP (Ministry of Interior)."
Cannot retract "Cannot retract subquota. Sub-recipient has already started or completed claiming process."
Quota cancelled "This quota has been cancelled by the administrator."
Invalid email "Please enter a valid email address."
OIB validation "Invalid OIB checksum. Please verify the number."


Last Updated: January 2026