Completed
Push — main ( dc9c2e...80557c )
by Jochen
05:20
created

shop_order_admin()   A

Complexity

Conditions 1

Size

Total Lines 10
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 9
nop 1
dl 0
loc 10
rs 9.95
c 0
b 0
f 0
1
"""
2
:Copyright: 2006-2020 Jochen Kupperschmidt
3
:License: Modified BSD, see LICENSE for details.
4
"""
5
6
from unittest.mock import patch
7
8
import pytest
9
10
from byceps.events.shop import ShopOrderCanceled, ShopOrderPaid
11
from byceps.services.shop.article import service as article_service
12
from byceps.services.shop.cart.models import Cart
13
from byceps.services.shop.order.models.order import Order
14
from byceps.services.shop.order import service as order_service
15
from byceps.services.shop.order.transfer.models import (
16
    PaymentMethod,
17
    PaymentState,
18
)
19
from testfixtures.shop_order import create_orderer
20
21
from tests.helpers import login_user
22
from tests.integration.services.shop.helpers import (
23
    create_article as _create_article,
24
)
25
26
27
@pytest.fixture(scope='package')
28
def shop_order_admin(make_admin):
29
    permission_ids = {
30
        'admin.access',
31
        'shop_order.cancel',
32
        'shop_order.mark_as_paid',
33
    }
34
    admin = make_admin('ShopOrderAdmin', permission_ids)
35
    login_user(admin.id)
36
    return admin
37
38
39
@pytest.fixture(scope='package')
40
def shop_order_admin_client(make_client, admin_app, shop_order_admin):
41
    return make_client(admin_app, user_id=shop_order_admin.id)
42
43
44
@pytest.fixture
45
def article1(shop):
46
    article = create_article(shop.id, 'item-001', 8)
47
    article_id = article.id
48
    yield article
49
    article_service.delete_article(article_id)
50
51
52
@pytest.fixture
53
def article2(shop):
54
    article = create_article(shop.id, 'item-002', 8)
55
    article_id = article.id
56
    yield article
57
    article_service.delete_article(article_id)
58
59
60
@pytest.fixture
61
def article3(shop):
62
    article = create_article(shop.id, 'item-003', 8)
63
    article_id = article.id
64
    yield article
65
    article_service.delete_article(article_id)
66
67
68
@pytest.fixture(scope='module')
69
def orderer_user(make_user_with_detail):
70
    return make_user_with_detail('Besteller')
71
72
73
@pytest.fixture(scope='module')
74
def orderer(orderer_user):
75
    return create_orderer(orderer_user)
76
77
78
@patch('byceps.signals.shop.order_canceled.send')
79
@patch('byceps.blueprints.admin.shop.order.views.order_email_service')
80
def test_cancel_before_paid(
81
    order_email_service_mock,
82
    order_canceled_signal_send_mock,
83
    storefront,
84
    article1,
85
    shop_order_admin,
86
    orderer_user,
87
    orderer,
88
    shop_order_admin_client,
89
):
90
    article = article1
91
92
    quantified_articles_to_order = {(article, 3)}
93
    placed_order = place_order(
94
        storefront.id, orderer, quantified_articles_to_order
95
    )
96
    order_before = get_order(placed_order.id)
97
98
    assert get_article_quantity(article.id) == 5
99
100
    assert_payment_is_open(order_before)
101
102
    url = f'/admin/shop/orders/{order_before.id}/cancel'
103
    form_data = {
104
        'reason': 'Dein Vorname ist albern!',
105
        'send_email': 'y',
106
    }
107
    response = shop_order_admin_client.post(url, data=form_data)
108
109
    order_afterwards = get_order(order_before.id)
110
    assert response.status_code == 302
111
    assert_payment(
112
        order_afterwards, None, PaymentState.canceled_before_paid, shop_order_admin.id
113
    )
114
115
    assert get_article_quantity(article.id) == 8
116
117
    order_email_service_mock.send_email_for_canceled_order_to_orderer.assert_called_once_with(
118
        placed_order.id
119
    )
120
121
    event = ShopOrderCanceled(
122
        occurred_at=order_afterwards.payment_state_updated_at,
123
        initiator_id=shop_order_admin.id,
124
        initiator_screen_name=shop_order_admin.screen_name,
125
        order_id=placed_order.id,
126
        order_number=placed_order.order_number,
127
        orderer_id=orderer_user.id,
128
        orderer_screen_name=orderer_user.screen_name,
129
    )
130
    order_canceled_signal_send_mock.assert_called_once_with(None, event=event)
131
132
    order_service.delete_order(placed_order.id)
133
134
135
@patch('byceps.signals.shop.order_canceled.send')
136
@patch('byceps.blueprints.admin.shop.order.views.order_email_service')
137
def test_cancel_before_paid_without_sending_email(
138
    order_email_service_mock,
139
    order_canceled_signal_send_mock,
140
    storefront,
141
    article2,
142
    shop_order_admin,
143
    orderer_user,
144
    orderer,
145
    shop_order_admin_client,
146
):
147
    article = article2
148
149
    quantified_articles_to_order = {(article, 3)}
150
    placed_order = place_order(
151
        storefront.id, orderer, quantified_articles_to_order
152
    )
153
154
    url = f'/admin/shop/orders/{placed_order.id}/cancel'
155
    form_data = {
156
        'reason': 'Dein Vorname ist albern!',
157
        # Sending e-mail is not requested.
158
    }
159
    response = shop_order_admin_client.post(url, data=form_data)
160
161
    order_afterwards = get_order(placed_order.id)
162
    assert response.status_code == 302
163
164
    # No e-mail should be send.
165
    order_email_service_mock.send_email_for_canceled_order_to_orderer.assert_not_called()
166
167
    event = ShopOrderCanceled(
168
        occurred_at=order_afterwards.payment_state_updated_at,
169
        initiator_id=shop_order_admin.id,
170
        initiator_screen_name=shop_order_admin.screen_name,
171
        order_id=placed_order.id,
172
        order_number=placed_order.order_number,
173
        orderer_id=orderer_user.id,
174
        orderer_screen_name=orderer_user.screen_name,
175
    )
176
    order_canceled_signal_send_mock.assert_called_once_with(None, event=event)
177
178
    order_service.delete_order(placed_order.id)
179
180
181
@patch('byceps.signals.shop.order_paid.send')
182
@patch('byceps.blueprints.admin.shop.order.views.order_email_service')
183
def test_mark_order_as_paid(
184
    order_email_service_mock,
185
    order_paid_signal_send_mock,
186
    storefront,
187
    shop_order_admin,
188
    orderer_user,
189
    orderer,
190
    shop_order_admin_client,
191
):
192
    placed_order = place_order(storefront.id, orderer, [])
193
    order_before = get_order(placed_order.id)
194
195
    assert_payment_is_open(order_before)
196
197
    url = f'/admin/shop/orders/{order_before.id}/mark_as_paid'
198
    form_data = {'payment_method': 'direct_debit'}
199
    response = shop_order_admin_client.post(url, data=form_data)
200
201
    order_afterwards = get_order(order_before.id)
202
    assert response.status_code == 302
203
    assert_payment(
204
        order_afterwards,
205
        PaymentMethod.direct_debit,
206
        PaymentState.paid,
207
        shop_order_admin.id,
208
    )
209
210
    order_email_service_mock.send_email_for_paid_order_to_orderer.assert_called_once_with(
211
        placed_order.id
212
    )
213
214
    event = ShopOrderPaid(
215
        occurred_at=order_afterwards.payment_state_updated_at,
216
        initiator_id=shop_order_admin.id,
217
        initiator_screen_name=shop_order_admin.screen_name,
218
        order_id=placed_order.id,
219
        order_number=placed_order.order_number,
220
        orderer_id=orderer_user.id,
221
        orderer_screen_name=orderer_user.screen_name,
222
        payment_method=PaymentMethod.direct_debit,
223
    )
224
    order_paid_signal_send_mock.assert_called_once_with(None, event=event)
225
226
    order_service.delete_order(placed_order.id)
227
228
229
@patch('byceps.signals.shop.order_canceled.send')
230
@patch('byceps.signals.shop.order_paid.send')
231
@patch('byceps.blueprints.admin.shop.order.views.order_email_service')
232
def test_cancel_after_paid(
233
    order_email_service_mock,
234
    order_paid_signal_send_mock,
235
    order_canceled_signal_send_mock,
236
    storefront,
237
    article3,
238
    shop_order_admin,
239
    orderer_user,
240
    orderer,
241
    shop_order_admin_client,
242
):
243
    article = article3
244
245
    quantified_articles_to_order = {(article, 3)}
246
    placed_order = place_order(
247
        storefront.id, orderer, quantified_articles_to_order
248
    )
249
    order_before = get_order(placed_order.id)
250
251
    assert get_article_quantity(article.id) == 5
252
253
    assert_payment_is_open(order_before)
254
255
    url = f'/admin/shop/orders/{order_before.id}/mark_as_paid'
256
    form_data = {'payment_method': 'bank_transfer'}
257
    response = shop_order_admin_client.post(url, data=form_data)
258
259
    url = f'/admin/shop/orders/{order_before.id}/cancel'
260
    form_data = {
261
        'reason': 'Dein Vorname ist albern!',
262
        'send_email': 'n',
263
    }
264
    response = shop_order_admin_client.post(url, data=form_data)
265
266
    order_afterwards = get_order(order_before.id)
267
    assert response.status_code == 302
268
    assert_payment(
269
        order_afterwards,
270
        PaymentMethod.bank_transfer,
271
        PaymentState.canceled_after_paid,
272
        shop_order_admin.id,
273
    )
274
275
    assert get_article_quantity(article.id) == 8
276
277
    order_email_service_mock.send_email_for_canceled_order_to_orderer.assert_called_once_with(
278
        placed_order.id
279
    )
280
281
    event = ShopOrderCanceled(
282
        occurred_at=order_afterwards.payment_state_updated_at,
283
        initiator_id=shop_order_admin.id,
284
        initiator_screen_name=shop_order_admin.screen_name,
285
        order_id=placed_order.id,
286
        order_number=placed_order.order_number,
287
        orderer_id=orderer_user.id,
288
        orderer_screen_name=orderer_user.screen_name,
289
    )
290
    order_canceled_signal_send_mock.assert_called_once_with(None, event=event)
291
292
    order_service.delete_order(placed_order.id)
293
294
295
# helpers
296
297
298
def create_article(shop_id, item_number, total_quantity):
299
    return _create_article(
300
        shop_id,
301
        item_number=item_number,
302
        description=item_number,
303
        total_quantity=total_quantity,
304
    )
305
306
307
def get_article_quantity(article_id):
308
    article = article_service.get_article(article_id)
309
    return article.quantity
310
311
312
def place_order(storefront_id, orderer, quantified_articles):
313
    cart = Cart()
314
315
    for article, quantity_to_order in quantified_articles:
316
        cart.add_item(article, quantity_to_order)
317
318
    order, _ = order_service.place_order(storefront_id, orderer, cart)
319
320
    return order
321
322
323
def assert_payment_is_open(order):
324
    assert order.payment_method is None  # default
325
    assert order.payment_state == PaymentState.open
326
    assert order.payment_state_updated_at is None
327
    assert order.payment_state_updated_by_id is None
328
329
330
def assert_payment(order, method, state, updated_by_id):
331
    assert order.payment_method == method
332
    assert order.payment_state == state
333
    assert order.payment_state_updated_at is not None
334
    assert order.payment_state_updated_by_id == updated_by_id
335
336
337
def get_order(order_id):
338
    return Order.query.get(order_id)
339