Skip to content

Commit

Permalink
Order refunder (#1989)
Browse files Browse the repository at this point in the history
* `OrderUnshipper`: do not set unpaid

* Explicitly test `OrderUnpaidSetter` service

* Banks choices

* Add banks translations + add not existed translations

* Order model `set_not_paid()` -> `refund()`
  • Loading branch information
nkiryanov authored Sep 26, 2023
1 parent ec6e6f6 commit 4a9fba8
Show file tree
Hide file tree
Showing 41 changed files with 786 additions and 402 deletions.
2 changes: 1 addition & 1 deletion src/amocrm/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def amocrm_course(mixer, course):
@pytest.fixture(autouse=True)
def _mock_tasks_with_paid_setter(mocker):
mocker.patch("orders.services.order_paid_setter.OrderPaidSetter.after_shipment", return_value=None)
mocker.patch("orders.services.order_unpaid_setter.OrderUnpaidSetter.after_unshipment", return_value=None)
mocker.patch("orders.services.order_refunder.OrderRefunder.update_integrations", return_value=None)
mocker.patch("studying.shipment_factory.unship", return_value=None)


Expand Down
2 changes: 1 addition & 1 deletion src/amocrm/tests/services/order/tests_order_pusher.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def not_paid_order_with_lead(factory, user, course, amocrm_lead):
@pytest.fixture
def returned_order_with_lead(factory, user, course, amocrm_lead):
order = factory.order(user=user, course=course, is_paid=True, author=user, amocrm_lead=amocrm_lead)
order.set_not_paid()
order.refund()
return order


Expand Down
4 changes: 2 additions & 2 deletions src/amocrm/tests/services/order/tests_order_returner.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ def mock_delete_transaction(mocker):
@pytest.fixture
def unpaid_order(mixer, paid_order_with_lead):
mixer.blend("amocrm.AmoCRMOrderTransaction", order=paid_order_with_lead, amocrm_id=876)
paid_order_with_lead.set_not_paid()
paid_order_with_lead.refund()
return paid_order_with_lead


@pytest.fixture
def unpaid_order_not_in_amo(paid_order_without_lead):
paid_order_without_lead.set_not_paid()
paid_order_without_lead.refund()
return paid_order_without_lead


Expand Down
6 changes: 5 additions & 1 deletion src/app/conf/email.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@
}

RECEIPTS_EMAIL = env("RECEIPTS_EMAIL", cast=str, default="[email protected]")

DANGEROUS_OPERATION_HAPPENED_EMAILS = env(
"DANGEROUS_OPERATION_HAPPENED_EMAILS",
cast=tuple,
default=[],
)

# Postmark template IDs
PASSWORDLESS_TOKEN_TEMPLATE_ID = env("PASSWORDLESS_TOKEN_TEMPLATE_ID", cast=str, default="passwordless-token")
Expand Down
3 changes: 3 additions & 0 deletions src/app/conf/integrations/banking/banking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from app.conf.environ import env

BANKS_REFUNDS_ENABLED = env("BANKS_REFUNDS_ENABLED", cast=bool, default=not env("DEBUG")) # by default the opposite to DEBUG
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions src/app/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@
)

include("conf/integrations/*.py")
include("conf/integrations/banking/*.py")
8 changes: 7 additions & 1 deletion src/banking/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
import uuid

from django.conf import settings
from django.utils.translation import gettext_lazy as _

if TYPE_CHECKING:
from django_stubs_ext import StrPromise

from orders.models import Order
from users.models import User

Expand All @@ -17,7 +20,7 @@ class Bank(metaclass=ABCMeta):
currency_symbol = "₽"
ue: int = 1 # ue stands for «условные единицы», this is some humour from 2000's
acquiring_percent: Decimal = Decimal(0) # we use it for analytics
name: str = "—"
name: "StrPromise" = _("—")

def __init__(
self,
Expand All @@ -37,6 +40,9 @@ def __init__(
def get_initial_payment_url(self) -> str:
raise NotImplementedError()

def refund(self) -> None:
return

def validate_order(self, order: "Order") -> None: # NOQA: B027
"""Hook to validate if order suites given bank"""
return
Expand Down
13 changes: 10 additions & 3 deletions src/banking/selector.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,22 @@
from tinkoff.credit import TinkoffCredit
from tinkoff.dolyame import Dolyame

BANKS = {
BANKS: dict[str, Type[Bank]] = {
"tinkoff_bank": TinkoffBank,
"tinkoff_credit": TinkoffCredit,
"stripe": StripeBank,
"dolyame": Dolyame,
"zero_price": ZeroPriceBank,
}

BANK_CHOICES = tuple(BANKS.keys())
BANK_KEYS = sorted(BANKS.keys())
BANK_CHOICES = [
(
bank_key,
BANKS[bank_key].name,
)
for bank_key in BANK_KEYS
]

DEFAULT_BANK = TinkoffBank

Expand All @@ -25,7 +32,7 @@ def get_bank(desired: str | None = None) -> Type[Bank]:
return DEFAULT_BANK

try:
return BANKS[desired] # type: ignore
return BANKS[desired]
except KeyError:
return DEFAULT_BANK

Expand Down
4 changes: 3 additions & 1 deletion src/banking/zero_price_bank.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

from rest_framework.exceptions import ValidationError

from django.utils.translation import gettext_lazy as _

from banking.base import Bank

if TYPE_CHECKING:
Expand All @@ -15,7 +17,7 @@ class ZeroPriceBank(Bank):
currency = "KIS"
currency_symbol = "💋"
acquiring_percent = Decimal(0)
name = "Бесплатно"
name = _("Zero Price")

def __init__(
self,
Expand Down
8 changes: 4 additions & 4 deletions src/homework/tests/api/tests_answer_retrieve.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def test_answers_with_parents_have_parent_field(api, question, answer, another_a


def test_403_for_not_purchased_users(api, answer, purchase):
purchase.set_not_paid()
purchase.refund()

api.get(
f"/api/v2/homework/answers/{answer.slug}/",
Expand All @@ -90,7 +90,7 @@ def test_403_for_not_purchased_users(api, answer, purchase):


def test_ok_for_superusers_even_when_they_did_not_purchase_the_course(api, answer, purchase):
purchase.set_not_paid()
purchase.refund()

api.user.is_superuser = True
api.user.save()
Expand All @@ -102,7 +102,7 @@ def test_ok_for_superusers_even_when_they_did_not_purchase_the_course(api, answe


def test_ok_for_users_with_permission_even_when_they_did_not_purchase_the_course(api, answer, purchase):
purchase.set_not_paid()
purchase.refund()

api.user.add_perm("homework.question.see_all_questions")

Expand All @@ -113,7 +113,7 @@ def test_ok_for_users_with_permission_even_when_they_did_not_purchase_the_course


def test_configurable_permissions_checking(api, answer, purchase, settings):
purchase.set_not_paid()
purchase.refund()

settings.DISABLE_HOMEWORK_PERMISSIONS_CHECKING = True

Expand Down
8 changes: 4 additions & 4 deletions src/homework/tests/api/tests_question_retrieve.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ def test_markdown(api, question):


def test_403_for_not_purchased_users(api, question, purchase):
purchase.set_not_paid()
purchase.refund()

api.get(f"/api/v2/homework/questions/{question.slug}/", expected_status_code=403)


def test_ok_for_superusers_even_when_they_did_not_purchase_the_course(api, question, purchase):
purchase.set_not_paid()
purchase.refund()

api.user.is_superuser = True
api.user.save()
Expand All @@ -37,7 +37,7 @@ def test_ok_for_superusers_even_when_they_did_not_purchase_the_course(api, quest


def test_ok_for_users_with_permission_even_when_they_did_not_purchase_the_course(api, question, purchase):
purchase.set_not_paid()
purchase.refund()

api.user.add_perm("homework.question.see_all_questions")

Expand All @@ -46,7 +46,7 @@ def test_ok_for_users_with_permission_even_when_they_did_not_purchase_the_course

def test_ok_if_user_has_not_purchased_but_permission_check_is_disabled(api, settings, question, purchase):
settings.DISABLE_HOMEWORK_PERMISSIONS_CHECKING = True
purchase.set_not_paid()
purchase.refund()

api.get(f"/api/v2/homework/questions/{question.slug}/", expected_status_code=200)

Expand Down
5 changes: 5 additions & 0 deletions src/homework/tests/reactions/test_reaction_creator.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
pytestmark = [pytest.mark.django_db]


@pytest.fixture(autouse=True)
def _set_locale(settings):
settings.LANGUAGE_CODE = "en"


@pytest.fixture
def create():
return lambda *args, **kwargs: ReactionCreator(*args, **kwargs)()
Expand Down
Loading

0 comments on commit 4a9fba8

Please sign in to comment.