~homeworkprod/byceps

ref: 342e5296ae417372e544ce931b442e98301c17a1 byceps/byceps/blueprints/site/shop/orders/views.py -rw-r--r-- 5.3 KiB
342e5296 — Jochen Kupperschmidt Require body blocks in base templates 2 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
"""
byceps.blueprints.site.shop.orders.views
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

:Copyright: 2006-2021 Jochen Kupperschmidt
:License: Revised BSD (see `LICENSE` file for details)
"""

from flask import abort, g, request
from flask_babel import gettext

from .....services.shop.order.email import service as order_email_service
from .....services.shop.order import service as order_service
from .....services.shop.order.transfer.models import PaymentState
from .....services.shop.storefront import service as storefront_service
from .....services.site import service as site_service
from .....services.snippet.transfer.models import Scope
from .....signals import shop as shop_signals
from .....util.framework.blueprint import create_blueprint
from .....util.framework.flash import flash_error, flash_success
from .....util.framework.templating import templated
from .....util.views import login_required, redirect_to

from ....site.snippet.templating import render_snippet_as_partial

from .forms import CancelForm


blueprint = create_blueprint('shop_orders', __name__)


@blueprint.route('')
@login_required
@templated
def index():
    """List orders placed by the current user in the storefront assigned
    to the current site.
    """
    site = site_service.get_site(g.site_id)

    storefront_id = site.storefront_id
    if storefront_id is not None:
        storefront = storefront_service.get_storefront(storefront_id)
        orders = order_service.get_orders_placed_by_user_for_shop(
            g.user.id, storefront.shop_id
        )
    else:
        orders = []

    return {
        'orders': orders,
        'PaymentState': PaymentState,
    }


@blueprint.route('/<uuid:order_id>')
@login_required
@templated
def view(order_id):
    """Show a single order (if it belongs to the current user and
    current site's storefront).
    """
    order = order_service.find_order_with_details(order_id)

    if order is None:
        abort(404)

    if not _is_order_placed_by_current_user(order):
        abort(404)

    site = site_service.get_site(g.site_id)
    storefront = storefront_service.get_storefront(site.storefront_id)
    if order.shop_id != storefront.shop_id:
        # Order does not belong to the current site's storefront.
        abort(404)

    template_context = {
        'order': order,
        'render_order_payment_method': _find_order_payment_method_label,
    }

    if order.is_open:
        template_context['payment_instructions'] = _get_payment_instructions(
            order
        )

    return template_context


def _find_order_payment_method_label(payment_method):
    return order_service.find_payment_method_label(payment_method)


def _get_payment_instructions(order):
    scope = Scope('shop', str(order.shop_id))
    context = {'order_number': order.order_number}

    return render_snippet_as_partial(
        'payment_instructions', scope=scope, context=context
    )


@blueprint.route('/<uuid:order_id>/cancel')
@login_required
@templated
def cancel_form(order_id, erroneous_form=None):
    """Show form to cancel an order."""
    order = _get_order_by_current_user_or_404(order_id)

    if order.is_canceled:
        flash_error(gettext('The order has already been canceled.'))
        return redirect_to('.view', order_id=order.id)

    if order.is_paid:
        flash_error(
            gettext(
                'The order has already been paid. You cannot cancel it yourself anymore.'
            )
        )
        return redirect_to('.view', order_id=order.id)

    form = erroneous_form if erroneous_form else CancelForm()

    return {
        'order': order,
        'form': form,
    }


@blueprint.route('/<uuid:order_id>/cancel', methods=['POST'])
@login_required
def cancel(order_id):
    """Set the payment status of a single order to 'canceled' and
    release the respective article quantities.
    """
    order = _get_order_by_current_user_or_404(order_id)

    if order.is_canceled:
        flash_error(gettext('The order has already been canceled.'))
        return redirect_to('.view', order_id=order.id)

    if order.is_paid:
        flash_error(
            gettext(
                'The order has already been paid. You cannot cancel it yourself anymore.'
            )
        )
        return redirect_to('.view', order_id=order.id)

    form = CancelForm(request.form)
    if not form.validate():
        return cancel_form(order_id, form)

    reason = form.reason.data.strip()

    try:
        event = order_service.cancel_order(order.id, g.user.id, reason)
    except order_service.OrderAlreadyCanceled:
        flash_error(
            gettext(
                'The order has already been canceled. The payment state cannot be changed anymore.'
            )
        )
        return redirect_to('.view', order_id=order.id)

    flash_success(gettext('Order has been canceled.'))

    order_email_service.send_email_for_canceled_order_to_orderer(order.id)

    shop_signals.order_canceled.send(None, event=event)

    return redirect_to('.view', order_id=order.id)


def _get_order_by_current_user_or_404(order_id):
    order = order_service.find_order(order_id)

    if order is None:
        abort(404)

    if not _is_order_placed_by_current_user(order):
        abort(404)

    return order


def _is_order_placed_by_current_user(order) -> bool:
    return order.placed_by_id == g.user.id