Total Complexity | 74 |
Total Lines | 600 |
Duplicated Lines | 29.67 % |
Coverage | 30.89% |
Changes | 0 |
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like byceps.blueprints.site.shop.orders.views often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | """ |
||
2 | byceps.blueprints.site.shop.orders.views |
||
3 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
||
4 | |||
5 | :Copyright: 2014-2024 Jochen Kupperschmidt |
||
6 | :License: Revised BSD (see `LICENSE` file for details) |
||
7 | """ |
||
8 | |||
9 | 1 | from decimal import Decimal |
|
10 | |||
11 | 1 | from flask import abort, current_app, g, request |
|
12 | 1 | from flask_babel import gettext |
|
13 | import structlog |
||
14 | 1 | ||
15 | 1 | from byceps.services.brand import brand_service |
|
16 | from byceps.services.email import ( |
||
17 | email_config_service, |
||
18 | email_footer_service, |
||
19 | email_service, |
||
20 | 1 | ) |
|
21 | 1 | from byceps.services.party import party_setting_service |
|
22 | 1 | from byceps.services.shop.cancellation_request import ( |
|
23 | 1 | cancellation_request_service, |
|
24 | 1 | ) |
|
25 | 1 | from byceps.services.shop.order import ( |
|
26 | 1 | order_command_service, |
|
27 | 1 | order_payment_service, |
|
28 | 1 | order_service, |
|
29 | 1 | ) |
|
30 | 1 | from byceps.services.shop.order.email import order_email_service |
|
31 | 1 | from byceps.services.shop.order.errors import OrderAlreadyCanceledError |
|
32 | 1 | from byceps.services.shop.order.models.order import PaymentState |
|
33 | from byceps.services.shop.payment import payment_gateway_service |
||
34 | 1 | from byceps.services.shop.shop import shop_service |
|
35 | from byceps.services.shop.storefront import storefront_service |
||
36 | from byceps.services.user import user_service |
||
37 | 1 | from byceps.signals import shop as shop_signals |
|
38 | from byceps.util.framework.blueprint import create_blueprint |
||
39 | from byceps.util.framework.flash import flash_error, flash_success |
||
40 | 1 | from byceps.util.framework.templating import templated |
|
41 | 1 | from byceps.util.l10n import get_user_locale |
|
42 | 1 | from byceps.util.views import login_required, redirect_to |
|
43 | 1 | ||
44 | from .forms import CancelForm, RequestFullRefundForm, RequestPartialRefundForm |
||
45 | |||
46 | |||
47 | log = structlog.get_logger() |
||
48 | |||
49 | |||
50 | blueprint = create_blueprint('shop_orders', __name__) |
||
51 | |||
52 | |||
53 | @blueprint.get('') |
||
54 | @login_required |
||
55 | @templated |
||
56 | def index(): |
||
57 | """List orders placed by the current user in the storefront assigned |
||
58 | to the current site. |
||
59 | """ |
||
60 | storefront_id = g.site.storefront_id |
||
61 | if storefront_id is not None: |
||
62 | 1 | storefront = storefront_service.get_storefront(storefront_id) |
|
63 | 1 | orders = order_service.get_orders_placed_by_user_for_storefront( |
|
64 | 1 | g.user.id, storefront.id |
|
65 | 1 | ) |
|
66 | else: |
||
67 | orders = [] |
||
68 | |||
69 | 1 | return { |
|
70 | 'orders': orders, |
||
71 | 1 | 'PaymentState': PaymentState, |
|
72 | } |
||
73 | |||
74 | 1 | ||
75 | 1 | @blueprint.get('/<uuid:order_id>') |
|
76 | @login_required |
||
77 | 1 | @templated |
|
78 | 1 | def view(order_id): |
|
79 | """Show a single order (if it belongs to the current user and |
||
80 | 1 | current site's storefront). |
|
81 | """ |
||
82 | 1 | order = order_service.find_order_with_details(order_id) |
|
83 | |||
84 | if order is None: |
||
85 | abort(404) |
||
86 | |||
87 | if not _is_order_placed_by_current_user(order): |
||
88 | 1 | abort(404) |
|
89 | |||
90 | storefront = storefront_service.get_storefront(g.site.storefront_id) |
||
91 | if order.storefront_id != storefront.id: |
||
92 | # Order does not belong to the current site's storefront. |
||
93 | abort(404) |
||
94 | 1 | ||
95 | 1 | shop = shop_service.get_shop(order.shop_id) |
|
96 | |||
97 | paypal_enabled = ( |
||
98 | payment_gateway_service.is_payment_gateway_enabled_for_storefront( |
||
99 | 1 | 'paypal', storefront.id |
|
100 | ) |
||
101 | ) |
||
102 | 1 | if paypal_enabled: |
|
103 | paypal_client_id = current_app.config.get('PAYPAL_CLIENT_ID') |
||
104 | else: |
||
105 | paypal_client_id = None |
||
106 | 1 | ||
107 | 1 | stripe_enabled = ( |
|
108 | payment_gateway_service.is_payment_gateway_enabled_for_storefront( |
||
109 | 1 | 'stripe', storefront.id |
|
110 | ) |
||
111 | ) |
||
112 | if stripe_enabled: |
||
113 | stripe_publishable_key = current_app.config.get( |
||
114 | 1 | 'STRIPE_PUBLISHABLE_KEY' |
|
115 | 1 | ) |
|
116 | 1 | else: |
|
117 | 1 | stripe_publishable_key = None |
|
118 | |||
119 | cancellation_request = cancellation_request_service.get_request_for_order( |
||
120 | order.id |
||
121 | ) |
||
122 | |||
123 | template_context = { |
||
124 | 'order': order, |
||
125 | 'shop_title': shop.title, |
||
126 | 'paypal_enabled': paypal_enabled, |
||
127 | 'paypal_client_id': paypal_client_id, |
||
128 | 'stripe_enabled': stripe_enabled, |
||
129 | 'stripe_publishable_key': stripe_publishable_key, |
||
130 | 'render_order_payment_method': _find_order_payment_method_label, |
||
131 | 'cancellation_requesting_enabled': _is_cancellation_requesting_enabled(), |
||
132 | 'cancellation_request': cancellation_request, |
||
133 | } |
||
134 | |||
135 | if order.is_open: |
||
136 | template_context['payment_instructions'] = _get_payment_instructions( |
||
137 | order |
||
138 | ) |
||
139 | |||
140 | return template_context |
||
141 | 1 | ||
142 | 1 | ||
143 | 1 | def _find_order_payment_method_label(payment_method): |
|
144 | return order_service.find_payment_method_label(payment_method) |
||
145 | |||
146 | |||
147 | def _is_cancellation_requesting_enabled() -> bool: |
||
148 | party_id = g.party.id if g.party else None |
||
149 | if party_id is None: |
||
150 | return False |
||
151 | |||
152 | cancellation_permitted = party_setting_service.find_setting_value( |
||
153 | party_id, 'order_cancellation_requesting_enabled' |
||
154 | ) |
||
155 | |||
156 | return cancellation_permitted == 'true' |
||
157 | |||
158 | |||
159 | def _get_payment_instructions(order) -> str | None: |
||
160 | language_code = get_user_locale(g.user) |
||
161 | |||
162 | result = order_payment_service.get_html_payment_instructions( |
||
163 | order, language_code |
||
164 | ) |
||
165 | if result.is_err(): |
||
166 | log.error( |
||
167 | 'Sending refund request confirmation email failed', |
||
168 | error=result.unwrap_err(), |
||
169 | ) |
||
170 | return None |
||
171 | |||
172 | return result.unwrap() |
||
173 | |||
174 | |||
175 | @blueprint.get('/<uuid:order_id>/cancel') |
||
176 | @login_required |
||
177 | @templated |
||
178 | def cancel_form(order_id, erroneous_form=None): |
||
179 | """Show form to cancel an order.""" |
||
180 | order = _get_order_by_current_user_or_404(order_id) |
||
181 | |||
182 | if order.is_canceled: |
||
183 | flash_error(gettext('The order has already been canceled.')) |
||
184 | return redirect_to('.view', order_id=order.id) |
||
185 | |||
186 | if order.is_paid: |
||
187 | flash_error( |
||
188 | gettext( |
||
189 | 'The order has already been paid. You cannot cancel it yourself anymore.' |
||
190 | ) |
||
191 | 1 | ) |
|
192 | 1 | return redirect_to('.view', order_id=order.id) |
|
193 | 1 | ||
194 | 1 | form = erroneous_form if erroneous_form else CancelForm() |
|
195 | |||
196 | return { |
||
197 | 'order': order, |
||
198 | 'form': form, |
||
199 | } |
||
200 | |||
201 | |||
202 | @blueprint.post('/<uuid:order_id>/cancel') |
||
203 | @login_required |
||
204 | def cancel(order_id): |
||
205 | """Set the payment state of a single order to 'canceled' and |
||
206 | release the respective product quantities. |
||
207 | """ |
||
208 | order = _get_order_by_current_user_or_404(order_id) |
||
209 | |||
210 | if order.is_canceled: |
||
211 | flash_error(gettext('The order has already been canceled.')) |
||
212 | return redirect_to('.view', order_id=order.id) |
||
213 | |||
214 | if order.is_paid: |
||
215 | flash_error( |
||
216 | gettext( |
||
217 | 'The order has already been paid. You cannot cancel it yourself anymore.' |
||
218 | ) |
||
219 | ) |
||
220 | 1 | return redirect_to('.view', order_id=order.id) |
|
221 | 1 | ||
222 | 1 | form = CancelForm(request.form) |
|
223 | 1 | if not form.validate(): |
|
224 | return cancel_form(order_id, form) |
||
225 | |||
226 | reason = form.reason.data.strip() |
||
227 | |||
228 | cancellation_result = order_command_service.cancel_order( |
||
229 | order.id, g.user, reason |
||
230 | ) |
||
231 | if cancellation_result.is_err(): |
||
232 | err = cancellation_result.unwrap_err() |
||
233 | if isinstance(err, OrderAlreadyCanceledError): |
||
234 | flash_error( |
||
235 | gettext( |
||
236 | 'The order has already been canceled. The payment state cannot be changed anymore.' |
||
237 | ) |
||
238 | ) |
||
239 | else: |
||
240 | flash_error(gettext('An unexpected error occurred.')) |
||
241 | return redirect_to('.view', order_id=order.id) |
||
242 | |||
243 | canceled_order, event = cancellation_result.unwrap() |
||
244 | |||
245 | flash_success(gettext('Order has been canceled.')) |
||
246 | |||
247 | order_email_service.send_email_for_canceled_order_to_orderer(canceled_order) |
||
248 | |||
249 | 1 | shop_signals.order_canceled.send(None, event=event) |
|
250 | 1 | ||
251 | 1 | return redirect_to('.view', order_id=canceled_order.id) |
|
252 | |||
253 | |||
254 | View Code Duplication | @blueprint.get('/<uuid:order_id>/request_cancellation') |
|
255 | @login_required |
||
256 | @templated |
||
257 | def request_cancellation_choices(order_id): |
||
258 | """Show choices to request cancellation of an order.""" |
||
259 | if not _is_cancellation_requesting_enabled(): |
||
260 | abort(403) |
||
261 | |||
262 | order = _get_order_by_current_user_or_404(order_id) |
||
263 | |||
264 | if order.is_canceled: |
||
265 | flash_error(gettext('The order has already been canceled.')) |
||
266 | return redirect_to('.view', order_id=order.id) |
||
267 | |||
268 | if not order.is_paid: |
||
269 | flash_error(gettext('The order has not been paid.')) |
||
270 | return redirect_to('.view', order_id=order.id) |
||
271 | |||
272 | request_for_order_number = ( |
||
273 | cancellation_request_service.get_request_for_order(order.id) |
||
274 | ) |
||
275 | if request_for_order_number: |
||
276 | flash_error('Es liegt bereits eine Stornierungsanfrage vor.') |
||
277 | return redirect_to('.view', order_id=order.id) |
||
278 | |||
279 | return { |
||
280 | 'order': order, |
||
281 | } |
||
282 | |||
283 | |||
284 | View Code Duplication | @blueprint.get('/<uuid:order_id>/request_cancellation/donate_everything') |
|
285 | @login_required |
||
286 | @templated |
||
287 | def donate_everything_form(order_id, erroneous_form=None): |
||
288 | """Show form to donate the full amount of an order.""" |
||
289 | if not _is_cancellation_requesting_enabled(): |
||
290 | abort(403) |
||
291 | |||
292 | order = _get_order_by_current_user_or_404(order_id) |
||
293 | |||
294 | if order.is_canceled: |
||
295 | flash_error(gettext('The order has already been canceled.')) |
||
296 | return redirect_to('.view', order_id=order.id) |
||
297 | |||
298 | if not order.is_paid: |
||
299 | flash_error(gettext('The order has not been paid.')) |
||
300 | return redirect_to('.view', order_id=order.id) |
||
301 | |||
302 | request_for_order_number = ( |
||
303 | cancellation_request_service.get_request_for_order(order.id) |
||
304 | ) |
||
305 | if request_for_order_number: |
||
306 | flash_error('Es liegt bereits eine Stornierungsanfrage vor.') |
||
307 | return redirect_to('.view', order_id=order.id) |
||
308 | |||
309 | return { |
||
310 | 1 | 'order': order, |
|
311 | 1 | } |
|
312 | 1 | ||
313 | 1 | ||
314 | @blueprint.post('/<uuid:order_id>/request_cancellation') |
||
315 | @login_required |
||
316 | def donate_everything(order_id): |
||
317 | """Donate the full amount of an order, then cancel the order.""" |
||
318 | if not _is_cancellation_requesting_enabled(): |
||
319 | abort(403) |
||
320 | |||
321 | order = _get_order_by_current_user_or_404(order_id) |
||
322 | |||
323 | if order.is_canceled: |
||
324 | flash_error(gettext('The order has already been canceled.')) |
||
325 | return redirect_to('.view', order_id=order.id) |
||
326 | |||
327 | if not order.is_paid: |
||
328 | flash_error(gettext('The order has not been paid.')) |
||
329 | return redirect_to('.view', order_id=order.id) |
||
330 | |||
331 | request_for_order_number = ( |
||
332 | cancellation_request_service.get_request_for_order(order.id) |
||
333 | ) |
||
334 | if request_for_order_number: |
||
335 | flash_error('Es liegt bereits eine Stornierungsanfrage vor.') |
||
336 | return redirect_to('.view', order_id=order.id) |
||
337 | |||
338 | amount_donation = order.total_amount.amount |
||
339 | |||
340 | cancellation_request = ( |
||
341 | cancellation_request_service.create_request_for_full_donation( |
||
342 | 1 | order.shop_id, |
|
343 | 1 | order.id, |
|
344 | 1 | order.order_number, |
|
345 | amount_donation, |
||
346 | ) |
||
347 | ) |
||
348 | |||
349 | reason = 'Ticketrückgabe und Spende des Bestellbetrags in voller Höhe wie angefordert' |
||
350 | |||
351 | cancellation_result = order_command_service.cancel_order( |
||
352 | order.id, g.user, reason |
||
353 | ) |
||
354 | if cancellation_result.is_err(): |
||
355 | err = cancellation_result.unwrap_err() |
||
356 | if isinstance(err, OrderAlreadyCanceledError): |
||
357 | flash_error( |
||
358 | gettext( |
||
359 | 'The order has already been canceled. The payment state cannot be changed anymore.' |
||
360 | ) |
||
361 | ) |
||
362 | else: |
||
363 | flash_error(gettext('An unexpected error occurred.')) |
||
364 | return redirect_to('.view', order_id=order.id) |
||
365 | |||
366 | canceled_order, event = cancellation_result.unwrap() |
||
367 | |||
368 | cancellation_request_service.accept_request(cancellation_request.id) |
||
369 | |||
370 | flash_success(gettext('Order has been canceled.')) |
||
371 | |||
372 | order_email_service.send_email_for_canceled_order_to_orderer(canceled_order) |
||
373 | |||
374 | shop_signals.order_canceled.send(None, event=event) |
||
375 | |||
376 | return redirect_to('.view', order_id=canceled_order.id) |
||
377 | |||
378 | |||
379 | @blueprint.get('/<uuid:order_id>/request_partial_refund') |
||
380 | @login_required |
||
381 | @templated |
||
382 | def request_partial_refund_form(order_id, erroneous_form=None): |
||
383 | """Show form to request a partial refund of an order.""" |
||
384 | if not _is_cancellation_requesting_enabled(): |
||
385 | abort(403) |
||
386 | |||
387 | order = _get_order_by_current_user_or_404(order_id) |
||
388 | |||
389 | if order.is_canceled: |
||
390 | 1 | flash_error(gettext('The order has already been canceled.')) |
|
391 | 1 | return redirect_to('.view', order_id=order.id) |
|
392 | 1 | ||
393 | 1 | if not order.is_paid: |
|
394 | flash_error(gettext('The order has not been paid.')) |
||
395 | return redirect_to('.view', order_id=order.id) |
||
396 | |||
397 | request_for_order_number = ( |
||
398 | cancellation_request_service.get_request_for_order(order.id) |
||
399 | ) |
||
400 | if request_for_order_number: |
||
401 | flash_error('Es liegt bereits eine Stornierungsanfrage vor.') |
||
402 | return redirect_to('.view', order_id=order.id) |
||
403 | |||
404 | form = erroneous_form if erroneous_form else RequestPartialRefundForm(order) |
||
405 | |||
406 | return { |
||
407 | 'order': order, |
||
408 | 'form': form, |
||
409 | } |
||
410 | |||
411 | |||
412 | View Code Duplication | @blueprint.post('/<uuid:order_id>/request_partial_refund') |
|
413 | @login_required |
||
414 | def request_partial_refund(order_id): |
||
415 | """Request a partial refund of an order.""" |
||
416 | if not _is_cancellation_requesting_enabled(): |
||
417 | abort(403) |
||
418 | |||
419 | order = _get_order_by_current_user_or_404(order_id) |
||
420 | |||
421 | if order.is_canceled: |
||
422 | 1 | flash_error(gettext('The order has already been canceled.')) |
|
423 | 1 | return redirect_to('.view', order_id=order.id) |
|
424 | 1 | ||
425 | if not order.is_paid: |
||
426 | flash_error(gettext('The order has not been paid.')) |
||
427 | return redirect_to('.view', order_id=order.id) |
||
428 | |||
429 | request_for_order_number = ( |
||
430 | cancellation_request_service.get_request_for_order(order.id) |
||
431 | ) |
||
432 | if request_for_order_number: |
||
433 | flash_error('Es liegt bereits eine Stornierungsanfrage vor.') |
||
434 | return redirect_to('.view', order_id=order.id) |
||
435 | |||
436 | form = RequestPartialRefundForm(order, request.form) |
||
437 | if not form.validate(): |
||
438 | return request_partial_refund_form(order_id, form) |
||
439 | |||
440 | amount_donation = form.amount_donation.data |
||
441 | amount_refund = order.total_amount.amount - amount_donation |
||
442 | recipient_name = form.recipient_name.data |
||
443 | recipient_iban = form.recipient_iban.data |
||
444 | |||
445 | cancellation_request_service.create_request_for_partial_refund( |
||
446 | order.shop_id, |
||
447 | order.id, |
||
448 | order.order_number, |
||
449 | amount_refund, |
||
450 | amount_donation, |
||
451 | recipient_name, |
||
452 | recipient_iban, |
||
453 | ) |
||
454 | |||
455 | _send_refund_request_confirmation_email(order.order_number, amount_refund) |
||
456 | |||
457 | flash_success('Die Stornierungsanfrage wurde übermittelt.') |
||
458 | |||
459 | return redirect_to('.view', order_id=order.id) |
||
460 | |||
461 | |||
462 | View Code Duplication | @blueprint.get('/<uuid:order_id>/request_full_refund') |
|
463 | @login_required |
||
464 | @templated |
||
465 | def request_full_refund_form(order_id, erroneous_form=None): |
||
466 | """Show form to request a full refund of an order.""" |
||
467 | if not _is_cancellation_requesting_enabled(): |
||
468 | 1 | abort(403) |
|
469 | |||
470 | order = _get_order_by_current_user_or_404(order_id) |
||
471 | |||
472 | if order.is_canceled: |
||
473 | flash_error(gettext('The order has already been canceled.')) |
||
474 | return redirect_to('.view', order_id=order.id) |
||
475 | |||
476 | if not order.is_paid: |
||
477 | flash_error(gettext('The order has not been paid.')) |
||
478 | return redirect_to('.view', order_id=order.id) |
||
479 | |||
480 | request_for_order_number = ( |
||
481 | cancellation_request_service.get_request_for_order(order.id) |
||
482 | ) |
||
483 | if request_for_order_number: |
||
484 | flash_error('Es liegt bereits eine Stornierungsanfrage vor.') |
||
485 | return redirect_to('.view', order_id=order.id) |
||
486 | |||
487 | form = erroneous_form if erroneous_form else RequestFullRefundForm() |
||
488 | |||
489 | return { |
||
490 | 'order': order, |
||
491 | 'form': form, |
||
492 | } |
||
493 | |||
494 | |||
495 | View Code Duplication | @blueprint.post('/<uuid:order_id>/request_full_refund') |
|
496 | @login_required |
||
497 | def request_full_refund(order_id): |
||
498 | """Request a full refund of an order.""" |
||
499 | if not _is_cancellation_requesting_enabled(): |
||
500 | abort(403) |
||
501 | |||
502 | 1 | order = _get_order_by_current_user_or_404(order_id) |
|
503 | |||
504 | if order.is_canceled: |
||
505 | flash_error(gettext('The order has already been canceled.')) |
||
506 | return redirect_to('.view', order_id=order.id) |
||
507 | |||
508 | if not order.is_paid: |
||
509 | flash_error(gettext('The order has not been paid.')) |
||
510 | return redirect_to('.view', order_id=order.id) |
||
511 | |||
512 | request_for_order_number = ( |
||
513 | cancellation_request_service.get_request_for_order(order.id) |
||
514 | 1 | ) |
|
515 | 1 | if request_for_order_number: |
|
516 | flash_error('Es liegt bereits eine Stornierungsanfrage vor.') |
||
517 | return redirect_to('.view', order_id=order.id) |
||
518 | |||
519 | form = RequestFullRefundForm(request.form) |
||
520 | if not form.validate(): |
||
521 | return request_full_refund_form(order_id, form) |
||
522 | |||
523 | amount_refund = order.total_amount.amount |
||
524 | recipient_name = form.recipient_name.data |
||
525 | recipient_iban = form.recipient_iban.data |
||
526 | |||
527 | cancellation_request_service.create_request_for_full_refund( |
||
528 | order.shop_id, |
||
529 | order.id, |
||
530 | order.order_number, |
||
531 | amount_refund, |
||
532 | recipient_name, |
||
533 | recipient_iban, |
||
534 | ) |
||
535 | |||
536 | _send_refund_request_confirmation_email(order.order_number, amount_refund) |
||
537 | |||
538 | flash_success('Die Stornierungsanfrage wurde übermittelt.') |
||
539 | |||
540 | return redirect_to('.view', order_id=order.id) |
||
541 | |||
542 | |||
543 | def _send_refund_request_confirmation_email( |
||
544 | order_number, amount_refund: Decimal |
||
545 | ) -> None: |
||
546 | email_config = email_config_service.get_config(g.brand_id) |
||
547 | |||
548 | email_address = user_service.get_email_address_data(g.user.id) |
||
549 | if (email_address is None) or not email_address.verified: |
||
550 | # Ignore this situation for now. |
||
551 | return |
||
552 | |||
553 | screen_name = g.user.screen_name or 'User' |
||
554 | |||
555 | brand = brand_service.get_brand(g.brand_id) |
||
556 | language_code = get_user_locale(g.user) |
||
557 | |||
558 | footer_result = email_footer_service.get_footer(brand, language_code) |
||
559 | if footer_result.is_err(): |
||
560 | log.error( |
||
561 | 'Sending refund request confirmation email failed', |
||
562 | error=footer_result.unwrap_err(), |
||
563 | ) |
||
564 | return |
||
565 | |||
566 | footer = footer_result.unwrap() |
||
567 | |||
568 | sender = email_config.sender |
||
569 | recipients = [email_address.address] |
||
570 | subject = 'Eingang deiner Anfrage zur Rückerstattung von Tickets' |
||
571 | body = ( |
||
572 | f'Hallo {screen_name},\n\n' |
||
573 | 'wir haben deine Anfrage zur Rückerstattung deiner Bestellung ' |
||
574 | f'{order_number} in Höhe von {amount_refund} € erhalten.\n\n' |
||
575 | 'Bitte beachte, dass die Abwicklung der Rückzahlung einige Zeit ' |
||
576 | 'in Anspruch nehmen kann. Danke für dein Verständnis.' |
||
577 | '\n\n' |
||
578 | ) + footer |
||
579 | |||
580 | email_service.enqueue_email(sender, recipients, subject, body) |
||
581 | |||
582 | |||
583 | # helpers |
||
584 | |||
585 | |||
586 | def _get_order_by_current_user_or_404(order_id): |
||
587 | order = order_service.find_order(order_id) |
||
588 | |||
589 | if order is None: |
||
590 | abort(404) |
||
591 | |||
592 | if not _is_order_placed_by_current_user(order): |
||
593 | abort(404) |
||
594 | |||
595 | return order |
||
596 | |||
597 | |||
598 | def _is_order_placed_by_current_user(order) -> bool: |
||
599 | return order.placed_by.id == g.user.id |
||
600 |