Skip to content

Commit

Permalink
TinkoffBank: method refund. (#2002)
Browse files Browse the repository at this point in the history
Also use lowercased token for signing requests
  • Loading branch information
nkiryanov authored Sep 26, 2023
1 parent 4a9fba8 commit e8cd9ce
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 12 deletions.
13 changes: 12 additions & 1 deletion src/tinkoff/bank.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@ class TinkoffBank(Bank):
def get_initial_payment_url(self) -> str:
return self.Init()["PaymentURL"]

def refund(self) -> None:
last_payment_notification = self.order.tinkoff_payment_notifications.order_by("-id")[0]

self.call(
"Cancel",
payload={
"PaymentId": last_payment_notification.payment_id,
"Receipt": self.get_receipt(),
},
)

def Init(self) -> dict:
return self.call(
"Init",
Expand Down Expand Up @@ -86,7 +97,7 @@ def _get_token(request: dict) -> str:
_request["Password"] = settings.TINKOFF_TERMINAL_PASSWORD

sorted_request = OrderedDict(sorted(_request.items(), key=lambda key, *args: key))
return sha256("".join(str(value) for value in sorted_request.values()).encode()).hexdigest().upper()
return sha256("".join(str(value) for value in sorted_request.values()).encode()).hexdigest()

@staticmethod
def get_notification_url() -> str:
Expand Down
50 changes: 50 additions & 0 deletions src/tinkoff/tests/bank_client/tests_tinkoff_refund.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import pytest

from tinkoff.bank import TinkoffBank

pytestmark = [
pytest.mark.django_db,
]


@pytest.fixture
def paid_tinkoff_order(order, mixer):
order.setattr_and_save("bank_id", "tinkoff_bank")
order.set_paid()

mixer.blend("tinkoff.PaymentNotification", order=order, payment_id=9001)
return order


@pytest.fixture
def refund_success_response():
return {
"Success": True,
"ErrorCode": "0",
"TerminalKey": "k3y",
"Status": "REFUNDED",
"PaymentId": "9001",
"OrderId": "8P4GtFYc3fuaoVTTMa9EZt",
"OriginalAmount": 10050000,
"NewAmount": 0,
}


@pytest.fixture(autouse=True)
def add_tinkoff_refund_response(respx_mock, refund_success_response):
return respx_mock.post("https://securepay.tinkoff.ru/v2/Cancel/").respond(json=refund_success_response)


@pytest.fixture
def tinkoff(paid_tinkoff_order):
return TinkoffBank(order=paid_tinkoff_order)


def test_send_correct_refund_request(tinkoff, retrieve_request_json):
tinkoff.refund()

refund_request = retrieve_request_json()
assert refund_request["PaymentId"] == 9001
assert "Receipt" in refund_request
assert "TerminalKey" in refund_request
assert "Token" in refund_request
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,17 @@ def reference_request():


def test_signature(tinkoff, reference_request):
assert tinkoff._get_token(reference_request) == "597C160C8C348FB14C63C820C54B712468923A74FD111AC6B0ECDA01FB5F4716"
assert tinkoff._get_token(reference_request) == "597c160c8c348fb14c63c820c54b712468923a74fd111ac6b0ecda01fb5f4716"


def test_signature_without_data_and_receipt(tinkoff, reference_request):
del reference_request["DATA"]
del reference_request["Receipt"]

assert tinkoff._get_token(reference_request) == "597C160C8C348FB14C63C820C54B712468923A74FD111AC6B0ECDA01FB5F4716"
assert tinkoff._get_token(reference_request) == "597c160c8c348fb14c63c820c54b712468923a74fd111ac6b0ecda01fb5f4716"


def test_signature_with_integer_int(tinkoff, reference_request):
reference_request["OrderId"] = 100500

assert tinkoff._get_token(reference_request) == "2F182D493F0488BDE0750D1BDB8B1DE3A10BBE0A38358A89C8EA93972A55F453"
assert tinkoff._get_token(reference_request) == "2f182d493f0488bde0750d1bdb8b1de3a10bbe0a38358a89c8ea93972a55f453"
8 changes: 8 additions & 0 deletions src/tinkoff/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import json
import pytest

from respx import MockRouter


@pytest.fixture
def course(factory):
Expand All @@ -17,3 +20,8 @@ def user(mixer):
@pytest.fixture
def order(factory, user, course):
return factory.order(user=user, item=course, price="100500")


@pytest.fixture
def retrieve_request_json(respx_mock: MockRouter):
return lambda: json.loads(respx_mock.calls.last.request.content)
8 changes: 0 additions & 8 deletions src/tinkoff/tests/dolyame_client/conftest.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import json
import pytest

from respx import MockRouter

from tinkoff.dolyame import Dolyame

pytestmark = [pytest.mark.django_db]
Expand All @@ -23,8 +20,3 @@ def _absolute_host(settings):
@pytest.fixture
def dolyame(order):
return Dolyame(order=order)


@pytest.fixture
def retrieve_request_json(respx_mock: MockRouter):
return lambda: json.loads(respx_mock.calls.last.request.content)

0 comments on commit e8cd9ce

Please sign in to comment.