1
|
|
|
""" |
2
|
|
|
:Copyright: 2006-2019 Jochen Kupperschmidt |
3
|
|
|
:License: Modified BSD, see LICENSE for details. |
4
|
|
|
""" |
5
|
|
|
|
6
|
|
|
from unittest.mock import patch |
7
|
|
|
|
8
|
|
|
from byceps.services.shop.article.models.article import Article |
9
|
|
|
from byceps.services.shop.cart.models import Cart |
10
|
|
|
from byceps.services.shop.order.models.order import Order |
11
|
|
|
from byceps.services.shop.order import service as order_service |
12
|
|
|
from byceps.services.shop.order.transfer.models import ( |
13
|
|
|
PaymentMethod, |
14
|
|
|
PaymentState, |
15
|
|
|
) |
16
|
|
|
|
17
|
|
|
from testfixtures.shop_order import create_orderer |
18
|
|
|
|
19
|
|
|
from tests.base import CONFIG_FILENAME_TEST_ADMIN |
20
|
|
|
from tests.helpers import ( |
21
|
|
|
assign_permissions_to_user, |
22
|
|
|
create_brand, |
23
|
|
|
create_email_config, |
24
|
|
|
create_party, |
25
|
|
|
create_user, |
26
|
|
|
create_user_with_detail, |
27
|
|
|
http_client, |
28
|
|
|
login_user, |
29
|
|
|
) |
30
|
|
|
from tests.services.shop.base import ShopTestBase |
31
|
|
|
|
32
|
|
|
|
33
|
|
|
class ShopAdminTestCase(ShopTestBase): |
34
|
|
|
|
35
|
|
|
def setUp(self): |
36
|
|
|
super().setUp(config_filename=CONFIG_FILENAME_TEST_ADMIN) |
37
|
|
|
|
38
|
|
|
self.admin = self.create_admin() |
39
|
|
|
self.orderer = create_user_with_detail('Besteller') |
40
|
|
|
|
41
|
|
|
create_email_config() |
42
|
|
|
|
43
|
|
|
self.shop = self.create_shop() |
44
|
|
|
self.create_order_number_sequence(self.shop.id, 'AEC-05-B') |
45
|
|
|
self.create_shop_fragment(self.shop.id, 'email_footer', 'kthxbye') |
46
|
|
|
|
47
|
|
|
brand = create_brand() |
48
|
|
|
party = create_party(brand.id) |
49
|
|
|
|
50
|
|
|
def create_admin(self): |
51
|
|
|
admin = create_user('Admin') |
52
|
|
|
|
53
|
|
|
permission_ids = { |
54
|
|
|
'admin.access', |
55
|
|
|
'shop_order.cancel', |
56
|
|
|
'shop_order.mark_as_paid', |
57
|
|
|
} |
58
|
|
|
assign_permissions_to_user(admin.id, 'admin', permission_ids) |
59
|
|
|
|
60
|
|
|
login_user(admin.id) |
61
|
|
|
|
62
|
|
|
return admin |
63
|
|
|
|
64
|
|
|
@patch('byceps.blueprints.shop.order.signals.order_canceled.send') |
65
|
|
|
@patch('byceps.blueprints.admin.shop.order.views.order_email_service') |
66
|
|
|
def test_cancel_before_paid( |
67
|
|
|
self, order_email_service_mock, order_canceled_signal_send_mock |
68
|
|
|
): |
69
|
|
|
article_before = self.create_article(self.shop.id, quantity=8) |
70
|
|
|
|
71
|
|
|
quantified_articles_to_order = {(article_before, 3)} |
72
|
|
|
placed_order = self.place_order(quantified_articles_to_order) |
73
|
|
|
order_before = get_order(placed_order.id) |
74
|
|
|
|
75
|
|
|
assert article_before.quantity == 5 |
76
|
|
|
|
77
|
|
|
assert_payment_is_open(order_before) |
78
|
|
|
|
79
|
|
|
url = '/admin/shop/orders/{}/cancel'.format(order_before.id) |
80
|
|
|
form_data = { |
81
|
|
|
'reason': 'Dein Vorname ist albern!', |
82
|
|
|
'send_email': 'y', |
83
|
|
|
} |
84
|
|
|
with http_client(self.app, user_id=self.admin.id) as client: |
85
|
|
|
response = client.post(url, data=form_data) |
86
|
|
|
|
87
|
|
|
order_afterwards = get_order(order_before.id) |
88
|
|
|
assert response.status_code == 302 |
89
|
|
|
assert_payment( |
90
|
|
|
order_afterwards, |
91
|
|
|
PaymentMethod.bank_transfer, |
92
|
|
|
PaymentState.canceled_before_paid, |
93
|
|
|
self.admin.id, |
94
|
|
|
) |
95
|
|
|
|
96
|
|
|
article_afterwards = Article.query.get(article_before.id) |
97
|
|
|
assert article_afterwards.quantity == 8 |
98
|
|
|
|
99
|
|
|
order_email_service_mock.send_email_for_canceled_order_to_orderer.assert_called_once_with( |
100
|
|
|
placed_order.id |
101
|
|
|
) |
102
|
|
|
|
103
|
|
|
order_canceled_signal_send_mock.assert_called_once_with( |
104
|
|
|
None, order_id=placed_order.id |
105
|
|
|
) |
106
|
|
|
|
107
|
|
|
@patch('byceps.blueprints.shop.order.signals.order_canceled.send') |
108
|
|
|
@patch('byceps.blueprints.admin.shop.order.views.order_email_service') |
109
|
|
|
def test_cancel_before_paid_without_sending_email( |
110
|
|
|
self, order_email_service_mock, order_canceled_signal_send_mock |
111
|
|
|
): |
112
|
|
|
article_before = self.create_article(self.shop.id, quantity=8) |
113
|
|
|
quantified_articles_to_order = {(article_before, 3)} |
114
|
|
|
placed_order = self.place_order(quantified_articles_to_order) |
115
|
|
|
|
116
|
|
|
url = '/admin/shop/orders/{}/cancel'.format(placed_order.id) |
117
|
|
|
form_data = { |
118
|
|
|
'reason': 'Dein Vorname ist albern!', |
119
|
|
|
# Sending e-mail is not requested. |
120
|
|
|
} |
121
|
|
|
with http_client(self.app, user_id=self.admin.id) as client: |
122
|
|
|
response = client.post(url, data=form_data) |
123
|
|
|
|
124
|
|
|
assert response.status_code == 302 |
125
|
|
|
|
126
|
|
|
# No e-mail should be send. |
127
|
|
|
order_email_service_mock.send_email_for_canceled_order_to_orderer.assert_not_called() |
128
|
|
|
|
129
|
|
|
order_canceled_signal_send_mock.assert_called_once_with( |
130
|
|
|
None, order_id=placed_order.id |
131
|
|
|
) |
132
|
|
|
|
133
|
|
|
@patch('byceps.blueprints.shop.order.signals.order_paid.send') |
134
|
|
|
@patch('byceps.blueprints.admin.shop.order.views.order_email_service') |
135
|
|
|
def test_mark_order_as_paid( |
136
|
|
|
self, order_email_service_mock, order_paid_signal_send_mock |
137
|
|
|
): |
138
|
|
|
placed_order = self.place_order([]) |
139
|
|
|
order_before = get_order(placed_order.id) |
140
|
|
|
|
141
|
|
|
assert_payment_is_open(order_before) |
142
|
|
|
|
143
|
|
|
url = '/admin/shop/orders/{}/mark_as_paid'.format(order_before.id) |
144
|
|
|
form_data = {'payment_method': 'direct_debit'} |
145
|
|
|
with http_client(self.app, user_id=self.admin.id) as client: |
146
|
|
|
response = client.post(url, data=form_data) |
147
|
|
|
|
148
|
|
|
order_afterwards = get_order(order_before.id) |
149
|
|
|
assert response.status_code == 302 |
150
|
|
|
assert_payment( |
151
|
|
|
order_afterwards, |
152
|
|
|
PaymentMethod.direct_debit, |
153
|
|
|
PaymentState.paid, |
154
|
|
|
self.admin.id, |
155
|
|
|
) |
156
|
|
|
|
157
|
|
|
order_email_service_mock.send_email_for_paid_order_to_orderer.assert_called_once_with( |
158
|
|
|
placed_order.id |
159
|
|
|
) |
160
|
|
|
|
161
|
|
|
order_paid_signal_send_mock.assert_called_once_with( |
162
|
|
|
None, order_id=placed_order.id |
163
|
|
|
) |
164
|
|
|
|
165
|
|
|
@patch('byceps.blueprints.shop.order.signals.order_canceled.send') |
166
|
|
|
@patch('byceps.blueprints.shop.order.signals.order_paid.send') |
167
|
|
|
@patch('byceps.blueprints.admin.shop.order.views.order_email_service') |
168
|
|
|
def test_cancel_after_paid( |
169
|
|
|
self, |
170
|
|
|
order_email_service_mock, |
171
|
|
|
order_paid_signal_send_mock, |
172
|
|
|
order_canceled_signal_send_mock, |
173
|
|
|
): |
174
|
|
|
article_before = self.create_article(self.shop.id, quantity=8) |
175
|
|
|
|
176
|
|
|
quantified_articles_to_order = {(article_before, 3)} |
177
|
|
|
placed_order = self.place_order(quantified_articles_to_order) |
178
|
|
|
order_before = get_order(placed_order.id) |
179
|
|
|
|
180
|
|
|
assert article_before.quantity == 5 |
181
|
|
|
|
182
|
|
|
assert_payment_is_open(order_before) |
183
|
|
|
|
184
|
|
|
url = '/admin/shop/orders/{}/mark_as_paid'.format(order_before.id) |
185
|
|
|
form_data = {'payment_method': 'bank_transfer'} |
186
|
|
|
with http_client(self.app, user_id=self.admin.id) as client: |
187
|
|
|
response = client.post(url, data=form_data) |
188
|
|
|
|
189
|
|
|
url = '/admin/shop/orders/{}/cancel'.format(order_before.id) |
190
|
|
|
form_data = { |
191
|
|
|
'reason': 'Dein Vorname ist albern!', |
192
|
|
|
'send_email': 'n', |
193
|
|
|
} |
194
|
|
|
with http_client(self.app, user_id=self.admin.id) as client: |
195
|
|
|
response = client.post(url, data=form_data) |
196
|
|
|
|
197
|
|
|
order_afterwards = get_order(order_before.id) |
198
|
|
|
assert response.status_code == 302 |
199
|
|
|
assert_payment( |
200
|
|
|
order_afterwards, |
201
|
|
|
PaymentMethod.bank_transfer, |
202
|
|
|
PaymentState.canceled_after_paid, |
203
|
|
|
self.admin.id, |
204
|
|
|
) |
205
|
|
|
|
206
|
|
|
article_afterwards = Article.query.get(article_before.id) |
207
|
|
|
assert article_afterwards.quantity == 8 |
208
|
|
|
|
209
|
|
|
order_email_service_mock.send_email_for_canceled_order_to_orderer.assert_called_once_with( |
210
|
|
|
placed_order.id |
211
|
|
|
) |
212
|
|
|
|
213
|
|
|
order_canceled_signal_send_mock.assert_called_once_with( |
214
|
|
|
None, order_id=placed_order.id |
215
|
|
|
) |
216
|
|
|
|
217
|
|
|
# helpers |
218
|
|
|
|
219
|
|
|
def place_order(self, quantified_articles): |
220
|
|
|
orderer = create_orderer(self.orderer) |
221
|
|
|
payment_method = PaymentMethod.bank_transfer |
222
|
|
|
cart = Cart() |
223
|
|
|
|
224
|
|
|
for article, quantity_to_order in quantified_articles: |
225
|
|
|
cart.add_item(article, quantity_to_order) |
226
|
|
|
|
227
|
|
|
return order_service.place_order( |
228
|
|
|
self.shop.id, orderer, payment_method, cart |
229
|
|
|
) |
230
|
|
|
|
231
|
|
|
|
232
|
|
|
def assert_payment_is_open(order): |
233
|
|
|
assert order.payment_method == PaymentMethod.bank_transfer # default |
234
|
|
|
assert order.payment_state == PaymentState.open |
235
|
|
|
assert order.payment_state_updated_at is None |
236
|
|
|
assert order.payment_state_updated_by_id is None |
237
|
|
|
|
238
|
|
|
|
239
|
|
|
def assert_payment(order, method, state, updated_by_id): |
240
|
|
|
assert order.payment_method == method |
241
|
|
|
assert order.payment_state == state |
242
|
|
|
assert order.payment_state_updated_at is not None |
243
|
|
|
assert order.payment_state_updated_by_id == updated_by_id |
244
|
|
|
|
245
|
|
|
|
246
|
|
|
def get_order(order_id): |
247
|
|
|
return Order.query.get(order_id) |
248
|
|
|
|