Skip to content

Commit 52bf8c4

Browse files
committed
Added some transaction retrying tests.
1 parent e1ca3ae commit 52bf8c4

5 files changed

Lines changed: 212 additions & 4 deletions

File tree

silver/models/transactions/transaction.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ def clean(self):
306306

307307
if self.amount:
308308
if self.amount > self.document.amount_to_be_charged_in_transaction_currency:
309-
message = "Amount is greater than the amount that should be charged in order " \
309+
message = "Amount is greater than what should be charged in order " \
310310
"to pay the billing document."
311311
raise ValidationError(message)
312312
else:

silver/tests/factories.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ class Meta:
172172
transaction_xe_rate = Decimal(1)
173173
state = Invoice.STATES.DRAFT
174174
issue_date = factory.LazyAttribute(
175-
lambda invoice: timezone.now().date() if invoice.state == Invoice.STATES.ISSUED else None
175+
lambda invoice: timezone.now().date() if invoice.state != Invoice.STATES.DRAFT else None
176176
)
177177

178178
@factory.post_generation

silver/tests/integration/test_documents_transactions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ def test_no_transaction_creation_for_issued_documents_case3(self):
128128
mock_execute = MagicMock()
129129
with patch.multiple(TriggeredProcessor, execute_transaction=mock_execute):
130130
expected_exception = ValidationError
131-
expected_message = "{'__all__': [u'Amount is greater than the amount that should be " \
131+
expected_message = "{'__all__': [u'Amount is greater than what should be " \
132132
"charged in order to pay the billing document.']}"
133133
try:
134134
TransactionFactory.create(invoice=invoice,

silver/tests/spec/test_transactions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ def test_add_transaction_with_amount_greater_than_what_should_be_charged(self):
371371
response = self.client.post(url, format='json', data=data)
372372

373373
expected_data = {
374-
'non_field_errors': [u"Amount is greater than the amount that should be charged in "
374+
'non_field_errors': [u"Amount is greater than what should be charged in "
375375
u"order to pay the billing document."]
376376
}
377377
self.assertEqual(response.data, expected_data)
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
import pytest
2+
from datetime import timedelta
3+
from django.core.exceptions import ValidationError
4+
from django.utils import timezone
5+
from mock import patch
6+
7+
from silver.models import Transaction, Invoice
8+
from silver.retry_patterns import RetryPatterns
9+
from silver.tests.factories import TransactionFactory, PaymentMethodFactory, InvoiceFactory, \
10+
DocumentEntryFactory, ProviderFactory
11+
12+
13+
@pytest.mark.django_db
14+
def test_retry_transaction():
15+
payment_method = PaymentMethodFactory.create(verified=True, canceled=False)
16+
transaction = TransactionFactory.create(state=Transaction.States.Failed,
17+
payment_method=payment_method)
18+
19+
assert transaction.retry()
20+
21+
22+
@pytest.mark.django_db
23+
def test_retry_already_retried_transaction():
24+
payment_method = PaymentMethodFactory.create(verified=True, canceled=False)
25+
transaction = TransactionFactory.create(state=Transaction.States.Failed,
26+
payment_method=payment_method)
27+
28+
TransactionFactory.create(retried_transaction=transaction)
29+
30+
with pytest.raises(ValidationError) as exception_info:
31+
transaction.retry()
32+
assert str(exception_info.value) == "[u'The transaction cannot be retried.']"
33+
34+
35+
@pytest.mark.django_db
36+
def test_retry_transaction_with_canceled_payment_method():
37+
payment_method = PaymentMethodFactory.create(verified=True, canceled=True)
38+
transaction = TransactionFactory.create(state=Transaction.States.Failed,
39+
payment_method=payment_method)
40+
41+
with pytest.raises(ValidationError) as exception_info:
42+
transaction.retry()
43+
assert str(exception_info.value) == "{'payment_method': " \
44+
"[u'The payment method is not recurring.']}"
45+
46+
47+
@pytest.mark.django_db
48+
def test_retry_transaction_of_paid_billing_document():
49+
payment_method = PaymentMethodFactory.create(verified=True, canceled=False)
50+
51+
invoice = InvoiceFactory.create(customer=payment_method.customer, state=Invoice.STATES.ISSUED)
52+
transaction = TransactionFactory.create(state=Transaction.States.Failed,
53+
payment_method=payment_method,
54+
invoice=invoice)
55+
56+
invoice.pay()
57+
58+
with pytest.raises(ValidationError) as exception_info:
59+
transaction.retry()
60+
assert str(exception_info.value) == "[u'The transaction cannot be retried.']"
61+
62+
63+
@pytest.mark.django_db
64+
def test_retry_transaction_of_canceled_billing_document():
65+
payment_method = PaymentMethodFactory.create(verified=True, canceled=False)
66+
67+
invoice = InvoiceFactory.create(customer=payment_method.customer, state=Invoice.STATES.ISSUED)
68+
transaction = TransactionFactory.create(state=Transaction.States.Failed,
69+
payment_method=payment_method,
70+
invoice=invoice)
71+
72+
invoice.cancel()
73+
74+
with pytest.raises(ValidationError) as exception_info:
75+
transaction.retry()
76+
assert str(exception_info.value) == "[u'The transaction cannot be retried.']"
77+
78+
79+
@pytest.mark.django_db
80+
def test_retry_transaction_with_amount_greater_than_remaining_payable_amount():
81+
payment_method = PaymentMethodFactory.create(verified=True, canceled=False)
82+
83+
entry = DocumentEntryFactory(quantity=1, unit_price=200)
84+
invoice = InvoiceFactory.create(customer=payment_method.customer, state=Invoice.STATES.ISSUED,
85+
invoice_entries=[entry])
86+
87+
transaction = TransactionFactory.create(state=Transaction.States.Failed,
88+
payment_method=payment_method,
89+
invoice=invoice, amount=150)
90+
91+
TransactionFactory.create(state=Transaction.States.Settled,
92+
payment_method=payment_method,
93+
invoice=invoice, amount=100)
94+
95+
with pytest.raises(ValidationError) as exception_info:
96+
transaction.retry()
97+
assert str(exception_info.value) == "{'__all__': [u'Amount is greater than what should be " \
98+
"charged in order to pay the billing document.']}"
99+
100+
101+
@pytest.mark.parametrize('state', [Transaction.States.Initial,
102+
Transaction.States.Pending,
103+
Transaction.States.Refunded,
104+
Transaction.States.Settled])
105+
@pytest.mark.django_db
106+
def test_retry_non_failed_transaction(state):
107+
payment_method = PaymentMethodFactory.create(verified=True, canceled=False)
108+
109+
transaction = TransactionFactory.create(state=state, payment_method=payment_method)
110+
111+
with pytest.raises(ValidationError) as exception_info:
112+
transaction.retry()
113+
assert str(exception_info.value) == "[u'The transaction cannot be retried.']"
114+
115+
116+
@pytest.mark.django_db
117+
def test_automatic_retries_count():
118+
transaction = TransactionFactory.create(state=Transaction.States.Failed)
119+
assert transaction.automatic_retries_count == 0
120+
121+
automatic_retrial = TransactionFactory.create(state=Transaction.States.Failed,
122+
retried_transaction=transaction,
123+
retrial_type=Transaction.RetryTypes.Automatic)
124+
125+
assert automatic_retrial.automatic_retries_count == 1
126+
127+
staff_retrial = TransactionFactory.create(state=Transaction.States.Failed,
128+
retried_transaction=automatic_retrial,
129+
retrial_type=Transaction.RetryTypes.Staff)
130+
131+
assert staff_retrial.automatic_retries_count == 1
132+
133+
last_automatic_retrial = TransactionFactory.create(
134+
state=Transaction.States.Failed,
135+
retried_transaction=staff_retrial,
136+
retrial_type=Transaction.RetryTypes.Automatic
137+
)
138+
139+
assert last_automatic_retrial.automatic_retries_count == 2
140+
141+
142+
@pytest.mark.django_db
143+
def test_next_retry_datetime_daily(monkeypatch):
144+
payment_method = PaymentMethodFactory.create(verified=True, canceled=False)
145+
146+
provider = ProviderFactory.create(transaction_retry_pattern='daily')
147+
148+
transaction = TransactionFactory.create(state=Transaction.States.Failed,
149+
payment_method=payment_method)
150+
151+
monkeypatch.setattr('silver.models.Transaction.provider', provider)
152+
monkeypatch.setattr('silver.models.Transaction.automatic_retries_count', 3)
153+
154+
assert transaction.next_retry_datetime == transaction.created_at + timedelta(days=1)
155+
156+
157+
@pytest.mark.django_db
158+
def test_next_retry_datetime_exponential(monkeypatch):
159+
payment_method = PaymentMethodFactory.create(verified=True, canceled=False)
160+
161+
provider = ProviderFactory.create(transaction_retry_pattern='exponential')
162+
163+
transaction = TransactionFactory.create(state=Transaction.States.Failed,
164+
payment_method=payment_method)
165+
166+
monkeypatch.setattr('silver.models.Transaction.provider', provider)
167+
monkeypatch.setattr('silver.models.Transaction.automatic_retries_count', 3)
168+
169+
# 2 ** 3 = 8
170+
assert transaction.next_retry_datetime == transaction.created_at + timedelta(days=8)
171+
172+
173+
@pytest.mark.django_db
174+
def test_next_retry_datetime_fibonacci(monkeypatch):
175+
payment_method = PaymentMethodFactory.create(verified=True, canceled=False)
176+
177+
provider = ProviderFactory.create(transaction_retry_pattern='fibonacci')
178+
179+
transaction = TransactionFactory.create(state=Transaction.States.Failed,
180+
payment_method=payment_method)
181+
182+
monkeypatch.setattr('silver.models.Transaction.provider', provider)
183+
monkeypatch.setattr('silver.models.Transaction.automatic_retries_count', 3)
184+
185+
# the 3rd number of the fibonacci series is 2
186+
assert transaction.next_retry_datetime == transaction.created_at + timedelta(days=2)
187+
188+
189+
@pytest.mark.django_db
190+
def test_should_be_automatically_retried(monkeypatch):
191+
transaction = TransactionFactory.create(created_at=timezone.now() - timedelta(days=1))
192+
193+
monkeypatch.setattr('silver.models.Transaction.can_be_retried', True)
194+
monkeypatch.setattr('silver.models.Transaction.automatic_retries_count',
195+
transaction.provider.transaction_maximum_automatic_retries)
196+
assert not transaction.should_be_automatically_retried
197+
198+
monkeypatch.setattr('silver.models.Transaction.automatic_retries_count', 0)
199+
monkeypatch.setattr('silver.models.Transaction.next_retry_datetime',
200+
timezone.now() + timedelta(days=1))
201+
assert not transaction.should_be_automatically_retried
202+
203+
monkeypatch.setattr('silver.models.Transaction.next_retry_datetime', timezone.now())
204+
monkeypatch.setattr('silver.models.Transaction.can_be_retried', False)
205+
assert not transaction.should_be_automatically_retried
206+
207+
monkeypatch.setattr('silver.models.Transaction.can_be_retried', True)
208+
assert transaction.should_be_automatically_retried

0 commit comments

Comments
 (0)