Passed
Push — master ( 9093b2...4379e5 )
by Jochen
02:11
created

byceps/blueprints/admin/shop/order/service.py (1 issue)

1
"""
2
byceps.blueprints.admin.shop.order.service
3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
5
:Copyright: 2006-2020 Jochen Kupperschmidt
6
:License: Modified BSD, see LICENSE for details.
7
"""
8
9
from dataclasses import dataclass
10
from typing import Dict, Iterator, Sequence
11
12
from .....services.shop.article.models.article import Article
13
from .....services.shop.article import service as article_service
14
from .....services.shop.article.transfer.models import ArticleNumber
15
from .....services.shop.order.models.order_event import (
16
    OrderEvent,
17
    OrderEventData,
18
)
19
from .....services.shop.order import event_service as order_event_service
20
from .....services.shop.order import service as order_service
21
from .....services.shop.order.transfer.models import Order, OrderID
22
from .....services.ticketing import category_service as ticket_category_service
23
from .....services.user.models.user import User as DbUser
24
from .....services.user import service as user_service
25
from .....services.user.transfer.models import User
26
from .....services.user_badge import service as user_badge_service
27
from .....typing import UserID
28
29
30
@dataclass(frozen=True)
31
class OrderWithOrderer(Order):
32
    placed_by: DbUser
33
34
35
def extend_order_tuples_with_orderer(
36
    orders: Sequence[Order]
37
) -> Iterator[OrderWithOrderer]:
38
    orderer_ids = {order.placed_by_id for order in orders}
39
    orderers = user_service.find_users(orderer_ids, include_avatars=True)
40
    orderers_by_id = user_service.index_users_by_id(orderers)
41
42
    for order in orders:
43
        orderer = orderers_by_id[order.placed_by_id]
44
        values = attr.astuple(order, recurse=False) + (orderer,)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable attr does not seem to be defined.
Loading history...
45
        yield OrderWithOrderer(*values)
46
47
48
def get_articles_by_item_number(order: Order) -> Dict[ArticleNumber, Article]:
49
    numbers = {item.article_number for item in order.items}
50
51
    articles = article_service.get_articles_by_numbers(numbers)
52
53
    return {article.item_number: article for article in articles}
54
55
56
def get_events(order_id: OrderID) -> Iterator[OrderEventData]:
57
    events = order_event_service.get_events_for_order(order_id)
58
    events.insert(0, _fake_order_placement_event(order_id))
59
60
    user_ids = {
61
        event.data['initiator_id']
62
        for event in events
63
        if 'initiator_id' in event.data
64
    }
65
    users = user_service.find_users(user_ids, include_avatars=True)
66
    users_by_id = {str(user.id): user for user in users}
67
68
    for event in events:
69
        data = {
70
            'event': event.event_type,
71
            'occurred_at': event.occurred_at,
72
            'data': event.data,
73
        }
74
75
        additional_data = _get_additional_data(event, users_by_id)
76
        data.update(additional_data)
77
78
        yield data
79
80
81
def _fake_order_placement_event(order_id: OrderID) -> OrderEvent:
82
    order = order_service.find_order_with_details(order_id)
83
    if order is None:
84
        raise ValueError('Unknown order ID')
85
86
    data = {
87
        'initiator_id': str(order.placed_by_id),
88
    }
89
90
    return OrderEvent(order.created_at, 'order-placed', order.id, data)
91
92
93
def _get_additional_data(
94
    event: OrderEvent, users_by_id: Dict[UserID, User]
95
) -> OrderEventData:
96
    if event.event_type == 'badge-awarded':
97
        return _get_additional_data_for_badge_awarded(event)
98
    elif event.event_type == 'ticket-bundle-created':
99
        return _get_additional_data_for_ticket_bundle_created(event)
100
    elif event.event_type == 'ticket-bundle-revoked':
101
        return _get_additional_data_for_ticket_bundle_revoked(
102
            event, users_by_id
103
        )
104
    elif event.event_type == 'ticket-created':
105
        return _get_additional_data_for_ticket_created(event)
106
    elif event.event_type == 'ticket-revoked':
107
        return _get_additional_data_for_ticket_revoked(event, users_by_id)
108
    else:
109
        return _get_additional_data_for_standard_event(event, users_by_id)
110
111
112
def _get_additional_data_for_standard_event(
113
    event: OrderEvent, users_by_id: Dict[UserID, User]
114
) -> OrderEventData:
115
    initiator_id = event.data['initiator_id']
116
117
    return {
118
        'initiator': users_by_id[initiator_id],
119
    }
120
121
122
def _get_additional_data_for_badge_awarded(event: OrderEvent) -> OrderEventData:
123
    badge_id = event.data['badge_id']
124
    badge = user_badge_service.find_badge(badge_id)
125
126
    recipient_id = event.data['recipient_id']
127
    recipient = user_service.find_user(recipient_id)
128
    recipient = _to_user_dto(recipient)
129
130
    return {
131
        'badge_label': badge.label,
132
        'recipient': recipient,
133
    }
134
135
136
def _get_additional_data_for_ticket_bundle_created(
137
    event: OrderEvent
138
) -> OrderEventData:
139
    bundle_id = event.data['ticket_bundle_id']
140
    category_id = event.data['ticket_bundle_category_id']
141
    ticket_quantity = event.data['ticket_bundle_ticket_quantity']
142
    owner_id = event.data['ticket_bundle_owner_id']
143
144
    category = ticket_category_service.find_category(category_id)
145
    category_title = category.title if (category is not None) else None
146
147
    return {
148
        'bundle_id': bundle_id,
149
        'ticket_category_title': category_title,
150
        'ticket_quantity': ticket_quantity,
151
    }
152
153
154
def _get_additional_data_for_ticket_bundle_revoked(
155
    event: OrderEvent, users_by_id: Dict[UserID, User]
156
) -> OrderEventData:
157
    bundle_id = event.data['ticket_bundle_id']
158
159
    data = {
160
        'bundle_id': bundle_id,
161
    }
162
163
    initiator_id = event.data.get('initiator_id')
164
    if initiator_id:
165
        data['initiator'] = users_by_id[initiator_id]
166
167
    return data
168
169
170
def _get_additional_data_for_ticket_created(
171
    event: OrderEvent
172
) -> OrderEventData:
173
    ticket_id = event.data['ticket_id']
174
    ticket_code = event.data['ticket_code']
175
    category_id = event.data['ticket_category_id']
176
    owner_id = event.data['ticket_owner_id']
177
178
    return {
179
        'ticket_id': ticket_id,
180
        'ticket_code': ticket_code,
181
    }
182
183
184
def _get_additional_data_for_ticket_revoked(
185
    event: OrderEvent, users_by_id: Dict[UserID, User]
186
) -> OrderEventData:
187
    ticket_id = event.data['ticket_id']
188
    ticket_code = event.data['ticket_code']
189
190
    data = {
191
        'ticket_code': ticket_code,
192
    }
193
194
    initiator_id = event.data.get('initiator_id')
195
    if initiator_id:
196
        data['initiator'] = users_by_id[initiator_id]
197
198
    return data
199
200
201
def _to_user_dto(user: DbUser) -> User:
202
    """Create an immutable user object with selected values from user entity."""
203
    avatar = getattr(user, 'avatar', None)
204
    avatar_url = avatar.url if avatar else None
205
    is_orga = False
206
207
    return User(
208
        user.id,
209
        user.screen_name,
210
        user.suspended,
211
        user.deleted,
212
        avatar_url,
213
        is_orga,
214
    )
215