Test Failed
Push — main ( 5f90c7...7c5752 )
by Jochen
04:45
created

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

1
"""
2
byceps.blueprints.admin.shop.order.views
3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
5
:Copyright: 2006-2021 Jochen Kupperschmidt
6
:License: Revised BSD (see `LICENSE` file for details)
7
"""
8
9 1
from flask import abort, g, request, Response
10 1
from flask_babel import gettext
11
12 1
from .....services.brand import service as brand_service
13 1
from .....services.shop.order import (
14 1
    event_service as order_event_service,
15
    sequence_service as order_sequence_service,
16
    service as order_service,
17
)
18
from .....services.shop.order.email import service as order_email_service
19 1
from .....services.shop.order.export import service as order_export_service
20 1
from .....services.shop.order.transfer.models import PaymentState
21 1
from .....services.shop.shop import service as shop_service
22 1
from .....services.ticketing import ticket_service
23 1
from .....services.user import service as user_service
24 1
from .....signals import shop as shop_signals
25 1
from .....util.framework.blueprint import create_blueprint
26 1
from .....util.framework.flash import flash_error, flash_notice, flash_success
27 1
from .....util.framework.templating import templated
28 1
from .....util.views import permission_required, redirect_to, respond_no_content
29 1
30
from .forms import (
31 1
    AddNoteForm,
32
    CancelForm,
33
    MarkAsPaidForm,
34
    OrderNumberSequenceCreateForm,
35
)
36
from .models import OrderStateFilter
37 1
from . import service
38 1
39
40
blueprint = create_blueprint('shop_order_admin', __name__)
41 1
42
43
@blueprint.get('/for_shop/<shop_id>', defaults={'page': 1})
44 1
@blueprint.get('/for_shop/<shop_id>/pages/<int:page>')
45 1
@permission_required('shop_order.view')
46 1
@templated
47 1
def index_for_shop(shop_id, page):
48
    """List orders for that shop."""
49
    shop = _get_shop_or_404(shop_id)
50
51
    brand = brand_service.get_brand(shop.brand_id)
52
53
    per_page = request.args.get('per_page', type=int, default=15)
54
55
    search_term = request.args.get('search_term', default='').strip()
56
57
    only_payment_state = request.args.get(
58
        'only_payment_state', type=PaymentState.__members__.get
59
    )
60
61
    def _str_to_bool(value):
62
        valid_values = {
63
            'true': True,
64
            'false': False,
65
        }
66
        return valid_values.get(value, False)
67
68
    only_processed = request.args.get('only_processed', type=_str_to_bool)
69
70
    order_state_filter = OrderStateFilter.find(
71
        only_payment_state, only_processed
72
    )
73
74
    orders = order_service.get_orders_for_shop_paginated(
75
        shop.id,
76
        page,
77
        per_page,
78
        search_term=search_term,
79
        only_payment_state=only_payment_state,
80
        only_processed=only_processed,
81
    )
82
83
    orders.items = list(service.extend_order_tuples_with_orderer(orders.items))
84
85
    return {
86
        'shop': shop,
87
        'brand': brand,
88
        'search_term': search_term,
89
        'PaymentState': PaymentState,
90
        'only_payment_state': only_payment_state,
91
        'only_processed': only_processed,
92
        'OrderStateFilter': OrderStateFilter,
93
        'order_state_filter': order_state_filter,
94
        'orders': orders,
95
        'render_order_payment_method': _find_order_payment_method_label,
96
    }
97
98
99
@blueprint.get('/<uuid:order_id>')
100 1
@permission_required('shop_order.view')
101 1
@templated
102 1
def view(order_id):
103
    """Show a single order."""
104
    order = order_service.find_order_with_details(order_id)
105
    if order is None:
106
        abort(404)
107
108
    placed_by = user_service.get_user(order.placed_by_id, include_avatar=True)
109
110
    shop = shop_service.get_shop(order.shop_id)
111
112
    brand = brand_service.get_brand(shop.brand_id)
113
114
    articles_by_item_number = service.get_articles_by_item_number(order)
115
116
    events = service.get_events(order.id)
117
118
    tickets = ticket_service.find_tickets_created_by_order(order.order_number)
119
120
    return {
121
        'shop': shop,
122
        'brand': brand,
123
        'order': order,
124
        'placed_by': placed_by,
125
        'articles_by_item_number': articles_by_item_number,
126
        'events': events,
127
        'PaymentState': PaymentState,
128
        'tickets': tickets,
129
        'render_order_payment_method': _find_order_payment_method_label,
130
    }
131
132
133
# -------------------------------------------------------------------- #
134
# export
135
136
137
@blueprint.get('/<uuid:order_id>/export')
138 1
@permission_required('shop_order.view')
139 1
def export(order_id):
140
    """Export the order as an XML document."""
141
    xml_export = order_export_service.export_order_as_xml(order_id)
142 1
143
    if xml_export is None:
144 1
        abort(404)
145 1
146
    return Response(
147 1
        xml_export['content'], content_type=xml_export['content_type']
148
    )
149
150
151
# -------------------------------------------------------------------- #
152
# notes
153
154
155
@blueprint.get('/<uuid:order_id>/notes/create')
156 1
@permission_required('shop_order.update')
157 1
@templated
158 1
def add_note_form(order_id, erroneous_form=None):
159 1
    """Show form to add a note to the order."""
160
    order = _get_order_or_404(order_id)
161
162
    shop = shop_service.get_shop(order.shop_id)
163
164
    brand = brand_service.get_brand(shop.brand_id)
165
166
    form = erroneous_form if erroneous_form else AddNoteForm()
167
168
    return {
169
        'shop': shop,
170
        'brand': brand,
171
        'order': order,
172
        'form': form,
173
    }
174
175
176
@blueprint.post('/<uuid:order_id>/notes')
177 1
@permission_required('shop_order.update')
178 1
def add_note(order_id):
179
    """Add a note to the order."""
180
    order = _get_order_or_404(order_id)
181
182
    form = AddNoteForm(request.form)
183
    if not form.validate():
184
        return add_note_form(order_id, form)
185
186
    text = form.text.data.strip()
187
188
    order_service.add_note(order.id, g.user.id, text)
189
190
    flash_success(gettext('Note has been added.'))
191
192
    return redirect_to('.view', order_id=order.id)
193
194
195
# -------------------------------------------------------------------- #
196
# flags
197
198
199
@blueprint.post('/<uuid:order_id>/flags/invoiced')
200 1
@permission_required('shop_order.update')
201 1
@respond_no_content
202 1
def set_invoiced_flag(order_id):
203
    """Mark the order as invoiced."""
204
    order = _get_order_or_404(order_id)
205
    initiator_id = g.user.id
206
207
    order_service.set_invoiced_flag(order.id, initiator_id)
208
209
    flash_success(
210
        gettext(
211
            'Order %(order_number)s has been marked as invoiced.',
212
            order_number=order.order_number,
213
        )
214
    )
215
216
217
@blueprint.delete('/<uuid:order_id>/flags/invoiced')
218 1
@permission_required('shop_order.update')
219 1
@respond_no_content
220 1
def unset_invoiced_flag(order_id):
221
    """Mark the order as not invoiced."""
222
    order = _get_order_or_404(order_id)
223
    initiator_id = g.user.id
224
225
    order_service.unset_invoiced_flag(order.id, initiator_id)
226
227
    flash_success(
228
        gettext(
229
            'Order %(order_number)s has been marked as not invoiced.',
230
            order_number=order.order_number,
231
        )
232
    )
233
234
235
@blueprint.post('/<uuid:order_id>/flags/shipped')
236 1
@permission_required('shop_order.update')
237 1
@respond_no_content
238 1
def set_shipped_flag(order_id):
239
    """Mark the order as shipped."""
240
    order = _get_order_or_404(order_id)
241
    initiator_id = g.user.id
242
243
    order_service.set_shipped_flag(order.id, initiator_id)
244
245
    flash_success(
246
        gettext(
247
            'Order %(order_number)s has been marked as shipped.',
248
            order_number=order.order_number,
249
        )
250
    )
251
252
253
@blueprint.delete('/<uuid:order_id>/flags/shipped')
254 1
@permission_required('shop_order.update')
255 1
@respond_no_content
256 1
def unset_shipped_flag(order_id):
257
    """Mark the order as not shipped."""
258
    order = _get_order_or_404(order_id)
259
    initiator_id = g.user.id
260
261
    order_service.unset_shipped_flag(order.id, initiator_id)
262
263
    flash_success(
264
        gettext(
265
            'Order %(order_number)s has been marked as not shipped.',
266
            order_number=order.order_number,
267
        )
268
    )
269
270
271
# -------------------------------------------------------------------- #
272
# cancel
273
274
275
@blueprint.get('/<uuid:order_id>/cancel')
276 1
@permission_required('shop_order.cancel')
277 1
@templated
278 1
def cancel_form(order_id, erroneous_form=None):
279 1
    """Show form to cancel an order."""
280
    order = _get_order_or_404(order_id)
281
282
    if order.is_canceled:
283
        flash_error(
284
            gettext(
285
                'The order has already been canceled. '
286
                'The payment state cannot be changed anymore.'
287
            )
288
        )
289
        return redirect_to('.view', order_id=order.id)
290
291
    shop = shop_service.get_shop(order.shop_id)
292
293
    brand = brand_service.get_brand(shop.brand_id)
294
295
    form = erroneous_form if erroneous_form else CancelForm()
296
297
    return {
298
        'shop': shop,
299
        'brand': brand,
300
        'order': order,
301
        'form': form,
302
    }
303
304
305
@blueprint.post('/<uuid:order_id>/cancel')
306 1
@permission_required('shop_order.cancel')
307 1
def cancel(order_id):
308
    """Set the payment state of a single order to 'canceled' and
309
    release the respective article quantities.
310
    """
311
    order = _get_order_or_404(order_id)
312 1
313
    form = CancelForm(request.form)
314 1
    if not form.validate():
315 1
        return cancel_form(order_id, form)
316
317
    reason = form.reason.data.strip()
318 1
    send_email = form.send_email.data
319 1
320
    try:
321 1
        event = order_service.cancel_order(order.id, g.user.id, reason)
322 1
    except order_service.OrderAlreadyCanceled:
323
        flash_error(
324
            gettext(
325
                'The order has already been canceled. '
326
                'The payment state cannot be changed anymore.'
327
            )
328
        )
329
        return redirect_to('.view', order_id=order.id)
330
331
    flash_success(
332 1
        gettext(
333
            'The order has been canceled and the corresponding articles '
334
            'have been made available again.'
335
        )
336
    )
337
338
    if send_email:
339 1
        order_email_service.send_email_for_canceled_order_to_orderer(order.id)
340 1
    else:
341
        flash_notice(gettext('No email has been sent to the orderer.'))
342 1
343
    shop_signals.order_canceled.send(None, event=event)
344 1
345
    return redirect_to('.view', order_id=order.id)
346 1
347
348
# -------------------------------------------------------------------- #
349
# mark as paid
350
351
352
@blueprint.get('/<uuid:order_id>/mark_as_paid')
353 1
@permission_required('shop_order.mark_as_paid')
354 1
@templated
355 1
def mark_as_paid_form(order_id, erroneous_form=None):
356 1
    """Show form to mark an order as paid."""
357
    order = _get_order_or_404(order_id)
358
359
    if order.is_paid:
360
        flash_error(gettext('Order is already marked as paid.'))
361
        return redirect_to('.view', order_id=order.id)
362
363
    shop = shop_service.get_shop(order.shop_id)
364
365
    brand = brand_service.get_brand(shop.brand_id)
366
367
    form = erroneous_form if erroneous_form else MarkAsPaidForm()
368
369
    return {
370
        'shop': shop,
371
        'brand': brand,
372
        'order': order,
373
        'form': form,
374
    }
375
376
377
@blueprint.post('/<uuid:order_id>/mark_as_paid')
378 1
@permission_required('shop_order.mark_as_paid')
379 1
def mark_as_paid(order_id):
380
    """Set the payment state of a single order to 'paid'."""
381
    order = _get_order_or_404(order_id)
382 1
383
    form = MarkAsPaidForm(request.form)
384 1
    if not form.validate():
385 1
        return mark_as_paid_form(order_id, form)
386
387
    payment_method = form.payment_method.data
388 1
    updated_by_id = g.user.id
389 1
390
    try:
391 1
        event = order_service.mark_order_as_paid(
392 1
            order.id, payment_method, updated_by_id
393
        )
394
    except order_service.OrderAlreadyMarkedAsPaid:
395
        flash_error(gettext('Order is already marked as paid.'))
396
        return redirect_to('.view', order_id=order.id)
397
398
    flash_success(gettext('Order has been marked as paid.'))
399 1
400
    order_email_service.send_email_for_paid_order_to_orderer(order.id)
401 1
402
    shop_signals.order_paid.send(None, event=event)
403 1
404
    return redirect_to('.view', order_id=order.id)
405 1
406
407
# -------------------------------------------------------------------- #
408
# email
409
410
411
@blueprint.post('/<uuid:order_id>/resend_incoming_order_email')
412 1
@permission_required('shop_order.update')
413 1
@respond_no_content
414 1
def resend_email_for_incoming_order_to_orderer(order_id):
415
    """Resend the e-mail to the orderer to confirm that the order was placed."""
416
    order = _get_order_or_404(order_id)
417
418
    initiator_id = g.user.id
419
420
    order_email_service.send_email_for_incoming_order_to_orderer(order.id)
421
422
    order_event_service.create_event(
423
        'order-placed-confirmation-email-resent',
424
        order.id,
425
        {
426
            'initiator_id': str(initiator_id),
427
        },
428
    )
429
430
    flash_success(
431
        gettext('Email confirmation for placed order has been sent again.')
432
    )
433
434
435
# -------------------------------------------------------------------- #
436
# order number sequences
437
438
439
@blueprint.get('/number_sequences/for_shop/<shop_id>/create')
440 1
@permission_required('shop.update')
441 1
@templated
442 1
def create_number_sequence_form(shop_id, erroneous_form=None):
443 1
    """Show form to create an order number sequence."""
444
    shop = _get_shop_or_404(shop_id)
445
446
    brand = brand_service.get_brand(shop.brand_id)
447
448
    form = erroneous_form if erroneous_form else OrderNumberSequenceCreateForm()
449
450
    return {
451
        'shop': shop,
452
        'brand': brand,
453
        'form': form,
454
    }
455
456
457 View Code Duplication
@blueprint.post('/number_sequences/for_shop/<shop_id>')
1 ignored issue
show
This code seems to be duplicated in your project.
Loading history...
458 1
@permission_required('shop.update')
459 1
def create_number_sequence(shop_id):
460
    """Create an order number sequence."""
461
    shop = _get_shop_or_404(shop_id)
462
463
    form = OrderNumberSequenceCreateForm(request.form)
464
    if not form.validate():
465
        return create_number_sequence_form(shop_id, form)
466
467
    prefix = form.prefix.data.strip()
468
469
    sequence_id = order_sequence_service.create_order_number_sequence(
470
        shop.id, prefix
471
    )
472
    if sequence_id is None:
473
        flash_error(
474
            gettext(
475
                'Order number sequence could not be created. '
476
                'Is the prefix "%(prefix)s" already defined?',
477
                prefix=prefix,
478
            )
479
        )
480
        return create_number_sequence_form(shop.id, form)
481
482
    flash_success(
483
        gettext(
484
            'Order number sequence with prefix "%(prefix)s" has been created.',
485
            prefix=prefix,
486
        )
487
    )
488
    return redirect_to('.index_for_shop', shop_id=shop.id)
489
490
491
# -------------------------------------------------------------------- #
492
# helpers
493
494
495
def _get_shop_or_404(shop_id):
496 1
    shop = shop_service.find_shop(shop_id)
497
498
    if shop is None:
499
        abort(404)
500
501
    return shop
502
503
504
def _get_order_or_404(order_id):
505 1
    order = order_service.find_order(order_id)
506 1
507
    if order is None:
508 1
        abort(404)
509
510
    return order
511 1
512
513
def _find_order_payment_method_label(payment_method):
514
    return order_service.find_payment_method_label(payment_method)
515