Skip to content

Commit 070e1ac

Browse files
committed
feat(backends): add tests for new backend
- test backend including error states - gracefully handle errors in views
1 parent 0b38d77 commit 070e1ac

3 files changed

Lines changed: 170 additions & 16 deletions

File tree

weblate_web/payments/backends.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,10 @@ def request(
591591
raise PaymentError(message)
592592

593593
# Fallback to standardad requests handing
594-
response.raise_for_status()
594+
try:
595+
response.raise_for_status()
596+
except requests.HTTPError as error:
597+
raise PaymentError(str(error)) from error
595598

596599
return response.json()
597600

weblate_web/payments/tests.py

Lines changed: 147 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
from weblate_web.tests import TEST_FAKTURACE, mock_vies
3232

33-
from .backends import FioBank, InvalidState, get_backend, list_backends
33+
from .backends import FioBank, InvalidState, PaymentError, get_backend, list_backends
3434
from .models import Customer, Payment
3535
from .validators import validate_vatin
3636

@@ -184,24 +184,31 @@ def test_vat_calculation(self):
184184
self.assertEqual(payment.amount_without_vat, 100)
185185

186186

187-
@override_settings(
188-
PAYMENT_DEBUG=True,
189-
PAYMENT_FAKTURACE=TEST_FAKTURACE,
190-
FIO_TOKEN="test-token", # noqa: S106
191-
)
192-
class BackendTest(TestCase):
187+
class BackendBaseTestCase(TestCase):
188+
backend_name: str = ""
189+
193190
def setUp(self):
194191
super().setUp()
195192
self.customer = Customer.objects.create(**CUSTOMER)
196193
self.payment = Payment.objects.create(
197-
customer=self.customer, amount=100, description="Test Item"
194+
customer=self.customer,
195+
amount=100,
196+
description="Test Item",
197+
backend=self.backend_name,
198198
)
199199

200200
def check_payment(self, state):
201201
payment = Payment.objects.get(pk=self.payment.pk)
202202
self.assertEqual(payment.state, state)
203203
return payment
204204

205+
206+
@override_settings(
207+
PAYMENT_DEBUG=True,
208+
PAYMENT_FAKTURACE=TEST_FAKTURACE,
209+
FIO_TOKEN="test-token", # noqa: S106
210+
)
211+
class BackendTest(BackendBaseTestCase):
205212
def test_pay(self):
206213
backend = get_backend("pay")(self.payment)
207214
self.assertIsNone(backend.initiate(None, "", ""))
@@ -273,6 +280,138 @@ def test_proforma(self):
273280
self.assertEqual(mail.outbox[0].subject, "Your payment on weblate.org")
274281

275282

283+
@override_settings(
284+
PAYMENT_DEBUG=True,
285+
THEPAY_MERCHANT_ID="00000000-0000-0000-0000-000000000000",
286+
THEPAY_PASSWORD="test-password", # noqa: S106
287+
THEPAY_PROJECT_ID="42",
288+
THEPAY_SERVER="demo.api.thepay.cz",
289+
)
290+
class ThePay2Test(BackendBaseTestCase):
291+
backend_name = "thepay2-card"
292+
293+
def setUp(self):
294+
super().setUp()
295+
self.backend = self.payment.get_payment_backend()
296+
297+
@responses.activate
298+
def test_pay(self):
299+
responses.post(
300+
"https://demo.api.thepay.cz/v1/projects/42/payments",
301+
json={
302+
"pay_url": "https://gate.thepay.cz/12345/pay",
303+
"detail_url": "https://gate.thepay.cz/12345/state",
304+
},
305+
)
306+
responses.get(
307+
f"https://demo.api.thepay.cz/v1/projects/42/payments/{self.payment.pk}?merchant_id=00000000-0000-0000-0000-000000000000",
308+
json={
309+
"uid": "efd7d8e6-2fa3-3c46-b475-51762331bf56",
310+
"project_id": 1,
311+
"order_id": "CZ12131415",
312+
"state": "paid",
313+
"currency": "CZK",
314+
"amount": 87654,
315+
"paid_amount": 87654,
316+
"created_at": "2019-01-01T12:00:00+00:00",
317+
"finished_at": "2019-01-01T12:00:00+00:00",
318+
"valid_to": "2019-01-01T12:00:00+00:00",
319+
"fee": 121,
320+
"description": "Some description of the payment purpose.",
321+
"description_for_merchant": "Some description for merchant.",
322+
"payment_method": "card",
323+
"pay_url": "https://gate.thepay.cz/12345/pay",
324+
"detail_url": "https://gate.thepay.cz/12345/state",
325+
"customer": {
326+
"name": "Joe Doe",
327+
"ip": "192.168.0.1",
328+
"email": "joe.doe@gmail.com",
329+
},
330+
"offset_account": {
331+
"iban": "CZ6508000000192000145399",
332+
"owner_name": "Joe Doe",
333+
},
334+
"offset_account_status": "not_available",
335+
"offset_account_determined_at": "2019-01-01T12:00:00+00:00",
336+
"card": {
337+
"number": "515735******2654",
338+
"expiration_date": "2022-05",
339+
"brand": "MASTERCARD",
340+
"type": "debit",
341+
},
342+
"events": [
343+
{
344+
"occured_at": "2021-04-20T11:05:49.000000Z",
345+
"type": "state_change",
346+
"data": "expired",
347+
}
348+
],
349+
"parent": {"recurring_payments_available": True},
350+
},
351+
)
352+
response = self.backend.initiate(None, "", "")
353+
self.assertIsNotNone(response)
354+
self.assertRedirects(
355+
response,
356+
"https://gate.thepay.cz/12345/pay",
357+
fetch_redirect_response=False,
358+
)
359+
self.check_payment(Payment.PENDING)
360+
self.assertTrue(self.backend.complete(None))
361+
self.check_payment(Payment.ACCEPTED)
362+
self.assertEqual(len(mail.outbox), 1)
363+
self.assertEqual(mail.outbox[0].subject, "Your payment on weblate.org")
364+
365+
@responses.activate
366+
def test_error(self):
367+
responses.post(
368+
"https://demo.api.thepay.cz/v1/projects/42/payments",
369+
status=400,
370+
)
371+
with self.assertRaises(PaymentError):
372+
self.backend.initiate(None, "", "")
373+
self.check_payment(Payment.NEW)
374+
375+
@responses.activate
376+
def test_error_message(self):
377+
responses.post(
378+
"https://demo.api.thepay.cz/v1/projects/42/payments",
379+
json={
380+
"message": "Something wrong",
381+
},
382+
status=400,
383+
)
384+
with self.assertRaises(PaymentError):
385+
self.backend.initiate(None, "", "")
386+
self.check_payment(Payment.NEW)
387+
388+
@responses.activate
389+
def test_error_collect(self):
390+
responses.post(
391+
"https://demo.api.thepay.cz/v1/projects/42/payments",
392+
json={
393+
"pay_url": "https://gate.thepay.cz/12345/pay",
394+
"detail_url": "https://gate.thepay.cz/12345/state",
395+
},
396+
)
397+
responses.get(
398+
f"https://demo.api.thepay.cz/v1/projects/42/payments/{self.payment.pk}?merchant_id=00000000-0000-0000-0000-000000000000",
399+
status=401,
400+
)
401+
response = self.backend.initiate(None, "", "")
402+
self.assertIsNotNone(response)
403+
self.assertRedirects(
404+
response,
405+
"https://gate.thepay.cz/12345/pay",
406+
fetch_redirect_response=False,
407+
)
408+
self.check_payment(Payment.PENDING)
409+
with self.assertRaises(PaymentError):
410+
self.backend.complete(None)
411+
self.check_payment(Payment.PENDING)
412+
self.assertEqual(len(mail.outbox), 0)
413+
414+
276415
class VATTest(SimpleTestCase):
277416
@responses.activate
278417
def test_validation_invalid(self):

weblate_web/views.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
process_donation,
7676
process_subscription,
7777
)
78-
from weblate_web.payments.backends import get_backend, list_backends
78+
from weblate_web.payments.backends import PaymentError, get_backend, list_backends
7979
from weblate_web.payments.forms import CustomerForm
8080
from weblate_web.payments.models import Customer, Payment
8181
from weblate_web.payments.validators import cache_vies_data, validate_vatin
@@ -385,14 +385,26 @@ def form_valid(self, form):
385385
# Actualy call the payment backend
386386
method = form.cleaned_data["method"]
387387
backend = get_backend(method)(self.object)
388-
result = backend.initiate(
389-
self.request,
390-
self.object.get_payment_url(),
391-
self.object.get_complete_url(),
392-
)
388+
try:
389+
result = backend.initiate(
390+
self.request,
391+
self.object.get_payment_url(),
392+
self.object.get_complete_url(),
393+
)
394+
except PaymentError as error:
395+
messages.error(
396+
self.request, gettext("Could not perform payment: %s") % error
397+
)
398+
return super().form_invalid(form)
393399
if result is not None:
394400
return result
395-
backend.complete(self.request)
401+
try:
402+
backend.complete(self.request)
403+
except PaymentError as error:
404+
messages.error(
405+
self.request, gettext("Could not complete payment: %s") % error
406+
)
407+
return super().form_invalid(form)
396408
return self.redirect_origin()
397409

398410

0 commit comments

Comments
 (0)