~homeworkprod/byceps

ref: 4237b3ec9496efe95dcce82bea3207ab9de4d520 byceps/byceps/services/ticketing/ticket_creation_service.py -rw-r--r-- 2.4 KiB
4237b3ec — Jochen Kupperschmidt Move ticketing blueprint into `site` subpackage 1 year, 11 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
"""
byceps.services.ticketing.ticket_creation_service
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

:Copyright: 2006-2020 Jochen Kupperschmidt
:License: Modified BSD, see LICENSE for details.
"""

from random import sample
from typing import Iterator, Optional, Sequence, Set

from ...database import db
from ...typing import UserID

from ..shop.order.transfer.models import OrderNumber

from .models.ticket import Ticket as DbTicket
from .models.ticket_bundle import TicketBundle as DbTicketBundle
from .transfer.models import TicketCategoryID, TicketCode


def create_ticket(
    category_id: TicketCategoryID,
    owned_by_id: UserID,
    *,
    order_number: Optional[OrderNumber] = None,
) -> Sequence[DbTicket]:
    """Create a single ticket."""
    tickets = create_tickets(
        category_id, owned_by_id, 1, order_number=order_number
    )
    return tickets[0]


def create_tickets(
    category_id: TicketCategoryID,
    owned_by_id: UserID,
    quantity: int,
    *,
    order_number: Optional[OrderNumber] = None,
) -> Sequence[DbTicket]:
    """Create a number of tickets of the same category for a single owner."""
    tickets = list(
        build_tickets(
            category_id, owned_by_id, quantity, order_number=order_number
        )
    )

    db.session.add_all(tickets)
    db.session.commit()

    return tickets


def build_tickets(
    category_id: TicketCategoryID,
    owned_by_id: UserID,
    quantity: int,
    *,
    bundle: Optional[DbTicketBundle] = None,
    order_number: Optional[OrderNumber] = None,
) -> Iterator[DbTicket]:
    if quantity < 1:
        raise ValueError('Ticket quantity must be positive.')

    codes: Set[TicketCode] = set()

    for _ in range(quantity):
        code = _generate_ticket_code_not_in(codes)
        codes.add(code)

        yield DbTicket(
            code,
            category_id,
            owned_by_id,
            bundle=bundle,
            order_number=order_number,
        )


_CODE_ALPHABET = 'BCDFGHJKLMNPQRSTVWXYZ'
_CODE_LENGTH = 5


def _generate_ticket_code() -> TicketCode:
    """Generate a ticket code.

    Generated codes are not necessarily unique!
    """
    return TicketCode(''.join(sample(_CODE_ALPHABET, _CODE_LENGTH)))


def _generate_ticket_code_not_in(codes: Set[TicketCode]) -> TicketCode:
    """Generate ticket codes and return the first one not in the set."""
    while True:
        code = _generate_ticket_code()
        if code not in codes:
            return code