Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refund throtling and logging #2017

Merged
merged 4 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/app/conf/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"notion-materials": "100/hour",
"promocode": "100/hour",
"purchase": "100/hour",
"order-refund": "5/day",
},
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
}
Expand Down
32 changes: 24 additions & 8 deletions src/locale/ru/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-09-25 17:58+0300\n"
"POT-Creation-Date: 2023-10-02 20:01+0300\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
"Language: \n"
Expand All @@ -31,6 +31,10 @@ msgstr "Да"
msgid "No"
msgstr "Нет"

#: banking/base.py:23
msgid "—"
msgstr ""

#: banking/models.py:10
msgid "Atol"
msgstr "Атол"
Expand Down Expand Up @@ -362,31 +366,43 @@ msgstr "Файл"
msgid "Material files"
msgstr "Файлы"

#: orders/admin/orders/actions.py:14
#: orders/admin/orders/actions.py:21
msgid "Set paid"
msgstr "Пометить оплаченным"

#: orders/admin/orders/actions.py:22
#: orders/admin/orders/actions.py:29
msgid "Refund"
msgstr "Вернуть"

#: orders/admin/orders/actions.py:30
#: orders/admin/orders/actions.py:45
#, python-brace-format
msgid "Orders {refunded_orders_as_message} refunded."
msgstr "Заказы {refunded_orders_as_message} возвращены."

#: orders/admin/orders/actions.py:51
#, python-brace-format
msgid "Orders {non_refunded_orders_as_message} have not been refunded. Up to 5 "
"refunds per day are allowed. Please come back tomorrow."
msgstr "Заказы {non_refunded_orders_as_message} не были возвращены. "
"Разрешено до 5 возвратов в день, попробуйте снова завтра."

#: orders/admin/orders/actions.py:56
msgid "Ship without payments"
msgstr "Допустить до уроков без оплаты"

#: orders/admin/orders/actions.py:41
#: orders/admin/orders/actions.py:67
msgid "Ship again if paid"
msgstr "Ещё раз выполнить (если заказ не оплачен — не выполнится)"

#: orders/admin/orders/actions.py:54 products/admin/courses/actions.py:40
#: orders/admin/orders/actions.py:80 products/admin/courses/actions.py:40
msgid "Generate diplomas"
msgstr "Сгенерировать дипломы"

#: orders/admin/orders/actions.py:64
#: orders/admin/orders/actions.py:90
msgid "Accept homework"
msgstr "Засчитать домашку"

#: orders/admin/orders/actions.py:73
#: orders/admin/orders/actions.py:99
msgid "Disaccept homework"
msgstr "Не засчитать домашку"

Expand Down
32 changes: 29 additions & 3 deletions src/orders/admin/orders/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,22 @@

from celery import group

from django.contrib import messages
from django.db.models import QuerySet
from django.http.request import HttpRequest
from django.utils.translation import gettext as _

from app.admin import admin
from orders import tasks
from orders.admin.orders.throttling import OrderRefundActionThrottle
from orders.models import Order
from studying.models import Study


def format_orders_for_message(orders: list[Order]) -> str:
return ", ".join(str(order.id) for order in orders)


@admin.action(description=_("Set paid"), permissions=["pay"])
def set_paid(modeladmin: Any, request: HttpRequest, queryset: QuerySet) -> None:
for order in queryset.iterator():
Expand All @@ -21,10 +28,29 @@ def set_paid(modeladmin: Any, request: HttpRequest, queryset: QuerySet) -> None:

@admin.action(description=_("Refund"), permissions=["unpay"])
def refund(modeladmin: Any, request: HttpRequest, queryset: QuerySet) -> None:
for order in queryset.iterator():
order.refund()
throttle = OrderRefundActionThrottle()
refunded_orders = []
non_refunded_orders = []

modeladmin.message_user(request, f"{queryset.count()} orders refunded")
for order in queryset.iterator():
if throttle.allow_request(request, view=modeladmin):
order.refund()
modeladmin.log_change(request, order, "Order refunded")
refunded_orders.append(order)
else:
non_refunded_orders.append(order)

if refunded_orders:
refunded_orders_as_message = format_orders_for_message(refunded_orders)
modeladmin.message_user(request, _(f"Orders {refunded_orders_as_message} refunded."))

if non_refunded_orders:
non_refunded_orders_as_message = format_orders_for_message(non_refunded_orders)
modeladmin.message_user(
request,
_(f"Orders {non_refunded_orders_as_message} have not been refunded. Up to 5 refunds per day are allowed. Please come back tomorrow."),
level=messages.ERROR,
)


@admin.action(description=_("Ship without payments"), permissions=["pay"])
Expand Down
9 changes: 9 additions & 0 deletions src/orders/admin/orders/throttling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from rest_framework.throttling import UserRateThrottle

from app.throttling import ConfigurableThrottlingMixin


class OrderRefundActionThrottle(ConfigurableThrottlingMixin, UserRateThrottle): # type: ignore
"""Throttle for order's admin action `refund`."""

scope = "order-refund"