byceps.services.seating.seating_area_service   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 175
Duplicated Lines 0 %

Test Coverage

Coverage 59.61%

Importance

Changes 0
Metric Value
eloc 110
dl 0
loc 175
ccs 31
cts 52
cp 0.5961
rs 10
c 0
b 0
f 0
wmc 13

10 Functions

Rating   Name   Duplication   Size   Complexity  
A _db_entity_to_area() 0 9 1
A _find_db_area() 0 2 1
A update_area() 0 23 2
A count_areas_for_party() 0 7 1
A get_areas_for_party() 0 7 1
A create_area() 0 23 1
A find_area_for_party_by_slug() 0 12 2
A find_area() 0 8 2
A delete_area() 0 4 1
A get_areas_with_seat_utilization() 0 40 1
1
"""
2
byceps.services.seating.seating_area_service
3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
5
:Copyright: 2014-2024 Jochen Kupperschmidt
6
:License: Revised BSD (see `LICENSE` file for details)
7
"""
8
9 1
from sqlalchemy import delete, select
10
11 1
from byceps.database import db
12
from byceps.services.party.models import PartyID
13 1
from byceps.services.ticketing.dbmodels.ticket import DbTicket
14 1
15 1
from .dbmodels.area import DbSeatingArea
16
from .dbmodels.seat import DbSeat
17 1
from .models import SeatingArea, SeatingAreaID, SeatUtilization
18 1
19 1
20
def create_area(
21
    party_id: PartyID,
22 1
    slug: str,
23
    title: str,
24
    *,
25
    image_filename: str | None = None,
26
    image_width: int | None = None,
27
    image_height: int | None = None,
28
) -> SeatingArea:
29
    """Create an area."""
30
    db_area = DbSeatingArea(
31
        party_id,
32 1
        slug,
33
        title,
34
        image_filename=image_filename,
35
        image_width=image_width,
36
        image_height=image_height,
37
    )
38
39
    db.session.add(db_area)
40
    db.session.commit()
41 1
42 1
    return _db_entity_to_area(db_area)
43
44 1
45
def update_area(
46
    area_id: SeatingAreaID,
47 1
    slug: str,
48
    title: str,
49
    image_filename: str | None,
50
    image_width: int | None,
51
    image_height: int | None,
52
) -> SeatingArea:
53
    """Update an area."""
54
    db_area = _find_db_area(area_id)
55
56
    if db_area is None:
57
        raise ValueError(f'Unknown seating area ID "{area_id}"')
58
59
    db_area.slug = slug
60
    db_area.title = title
61
    db_area.image_filename = image_filename
62
    db_area.image_width = image_width
63
    db_area.image_height = image_height
64
65
    db.session.commit()
66
67
    return _db_entity_to_area(db_area)
68
69
70
def delete_area(area_id: SeatingAreaID) -> None:
71
    """Delete an area."""
72 1
    db.session.execute(delete(DbSeatingArea).filter_by(id=area_id))
73
    db.session.commit()
74 1
75 1
76
def count_areas_for_party(party_id: PartyID) -> int:
77
    """Return the number of seating areas for that party."""
78 1
    return (
79
        db.session.scalar(
80 1
            select(db.func.count(DbSeatingArea.id)).filter_by(party_id=party_id)
81
        )
82
        or 0
83
    )
84
85 1
86
def find_area(area_id: SeatingAreaID) -> SeatingArea | None:
87
    """Return the area, or `None` if not found."""
88
    db_area = _find_db_area(area_id)
89
90
    if db_area is None:
91
        return None
92
93
    return _db_entity_to_area(db_area)
94
95 1
96
def _find_db_area(area_id: SeatingAreaID) -> DbSeatingArea | None:
97
    return db.session.get(DbSeatingArea, area_id)
98
99 1
100
def find_area_for_party_by_slug(
101
    party_id: PartyID, slug: str
102
) -> SeatingArea | None:
103
    """Return the area for that party with that slug, or `None` if not found."""
104
    db_area = db.session.scalars(
105
        select(DbSeatingArea).filter_by(party_id=party_id).filter_by(slug=slug)
106
    ).first()
107
108
    if db_area is None:
109
        return None
110
111
    return _db_entity_to_area(db_area)
112
113 1
114
def get_areas_for_party(party_id: PartyID) -> list[SeatingArea]:
115
    """Return all areas for that party."""
116
    db_areas = db.session.scalars(
117
        select(DbSeatingArea).filter_by(party_id=party_id)
118
    ).all()
119
120
    return [_db_entity_to_area(db_area) for db_area in db_areas]
121
122 1
123
def get_areas_with_seat_utilization(
124
    party_id: PartyID,
125
) -> list[tuple[SeatingArea, SeatUtilization]]:
126 1
    """Return all areas and their seat utilization for that party."""
127
    area = db.aliased(DbSeatingArea)
128 1
129
    subquery_occupied_seat_count = (
130
        select(db.func.count(DbTicket.id))
131
        .filter(DbTicket.revoked == False)  # noqa: E712
132
        .filter(DbTicket.occupied_seat_id.is_not(None))
133
        .join(DbSeat)
134
        .filter(DbSeat.area_id == area.id)
135
        .scalar_subquery()
136
    )
137 1
138
    subquery_total_seat_count = (
139
        select(db.func.count(DbSeat.id))
140
        .filter_by(area_id=area.id)
141
        .scalar_subquery()
142
    )
143 1
144
    rows = db.session.execute(
145
        select(
146
            area,
147
            subquery_occupied_seat_count,
148
            subquery_total_seat_count,
149
        )
150
        .filter(area.party_id == party_id)
151
        .group_by(area.id)
152
        .order_by(area.title)
153
    ).all()
154 1
155
    return [
156
        (
157
            _db_entity_to_area(db_area),
158
            SeatUtilization(
159
                occupied=occupied_seat_count, total=total_seat_count
160
            ),
161
        )
162
        for db_area, occupied_seat_count, total_seat_count in rows
163
    ]
164
165 1
166 1
def _db_entity_to_area(db_area: DbSeatingArea) -> SeatingArea:
167
    return SeatingArea(
168
        id=db_area.id,
169
        party_id=db_area.party_id,
170
        slug=db_area.slug,
171
        title=db_area.title,
172
        image_filename=db_area.image_filename,
173
        image_width=db_area.image_width,
174
        image_height=db_area.image_height,
175
    )
176