# -*- encoding: utf-8 -*-
import pytest
from datetime import date
from dateutil.relativedelta import relativedelta
from decimal import Decimal
from unittest import mock
from checkout.models import (
CheckoutError,
CheckoutState,
PaymentRun,
PaymentRunItem,
)
from checkout.tests.factories import (
CustomerFactory,
ObjectPaymentPlanFactory,
ObjectPaymentPlanInstalmentFactory,
)
from example_checkout.tests.factories import SalesLedgerFactory
from mail.models import Message
from mail.tests.factories import NotifyFactory
def _instalment():
"""Create an instalment."""
return ObjectPaymentPlanInstalmentFactory(
object_payment_plan=ObjectPaymentPlanFactory(
content_object=SalesLedgerFactory()
),
state=CheckoutState.objects.pending,
)
[docs]@pytest.mark.django_db
def test_item_count():
obj = PaymentRun.objects.create_payment_run()
PaymentRunItem.objects.create_payment_run_item(obj, _instalment())
PaymentRunItem.objects.create_payment_run_item(obj, _instalment())
assert 2 == obj.item_count()
[docs]@pytest.mark.django_db
def test_item_count_zero():
obj = PaymentRun.objects.create_payment_run()
assert 0 == obj.item_count()
[docs]@pytest.mark.django_db
def test_manager():
obj = PaymentRun.objects.create_payment_run()
assert date.today() == obj.created.date()
[docs]@pytest.mark.django_db
def test_process_payments(mocker):
"""Process payments."""
mocker.patch("stripe.Charge.create")
mocker.patch("stripe.Customer.create")
today = date.today()
install = ObjectPaymentPlanInstalmentFactory(
due=today + relativedelta(days=-1),
amount=Decimal("2"),
count=2,
object_payment_plan=ObjectPaymentPlanFactory(
content_object=SalesLedgerFactory()
),
state=CheckoutState.objects.pending,
)
CustomerFactory(
email=install.object_payment_plan.content_object.checkout_email
)
NotifyFactory()
assert (1, 0) == PaymentRun.objects.process_payments()
install.refresh_from_db()
assert CheckoutState.objects.success == install.state
assert 1 == install.retry_count
# payment run
assert 1 == PaymentRun.objects.count()
payment_run = PaymentRun.objects.first()
assert 1 == payment_run.paymentrunitem_set.count()
payment_run_item = payment_run.paymentrunitem_set.first()
assert install.pk == payment_run_item.instalment.pk
assert payment_run_item.checkout is not None
assert CheckoutState.SUCCESS == payment_run_item.checkout.state.slug
# mail
assert 1 == Message.objects.count()
message = Message.objects.first()
assert "Payment plan activity update" in message.subject
assert "Processed 1 payment transaction" in message.description
assert "failed" not in message.description
[docs]@pytest.mark.django_db
def test_process_payments_retry(mocker):
"""Process various payments."""
mocker.patch("stripe.Charge.create")
mocker.patch("stripe.Customer.create")
today = date.today()
install_1 = ObjectPaymentPlanInstalmentFactory(
due=today + relativedelta(days=1),
amount=Decimal("1"),
count=2,
object_payment_plan=ObjectPaymentPlanFactory(
content_object=SalesLedgerFactory()
),
)
install_2 = ObjectPaymentPlanInstalmentFactory(
due=today + relativedelta(days=-1),
amount=Decimal("2"),
count=2,
object_payment_plan=ObjectPaymentPlanFactory(
content_object=SalesLedgerFactory()
),
state=CheckoutState.objects.fail,
)
install_3 = ObjectPaymentPlanInstalmentFactory(
due=today + relativedelta(days=-2),
amount=Decimal("3"),
count=2,
object_payment_plan=ObjectPaymentPlanFactory(
content_object=SalesLedgerFactory()
),
retry_count=1,
)
CustomerFactory(
email=install_2.object_payment_plan.content_object.checkout_email
)
CustomerFactory(
email=install_3.object_payment_plan.content_object.checkout_email
)
NotifyFactory()
assert (2, 0) == PaymentRun.objects.process_payments()
# check
install_1.refresh_from_db()
assert CheckoutState.objects.pending == install_1.state
assert install_1.retry_count is None
install_2.refresh_from_db()
assert CheckoutState.objects.success == install_2.state
assert 1 == install_2.retry_count
install_3.refresh_from_db()
assert CheckoutState.objects.success == install_3.state
assert 2 == install_3.retry_count
# payment run
assert 1 == PaymentRun.objects.count()
payment_run = PaymentRun.objects.first()
assert 2 == payment_run.paymentrunitem_set.count()
# mail
assert 1 == Message.objects.count()
message = Message.objects.first()
assert "Payment plan activity update" in message.subject
assert "Processed 2 payment transaction" in message.description
assert "failed" not in message.description
[docs]@pytest.mark.django_db
def test_process_payments_fail(mocker):
"""Process payments."""
with mock.patch("stripe.Customer.create") as mock_customer:
mock_customer.side_effect = CheckoutError("Mock")
today = date.today()
install = ObjectPaymentPlanInstalmentFactory(
due=today + relativedelta(days=-1),
amount=Decimal("1"),
object_payment_plan=ObjectPaymentPlanFactory(
content_object=SalesLedgerFactory()
),
)
CustomerFactory(
email=install.object_payment_plan.content_object.checkout_email
)
NotifyFactory()
assert (1, 1) == PaymentRun.objects.process_payments()
# check
install.refresh_from_db()
assert install.state == CheckoutState.objects.fail
assert 1 == Message.objects.count()
message = Message.objects.first()
assert "Payment plan activity update" in message.subject
assert "Processed 1 payment transaction" in message.description
assert "1 failed transaction" in message.description
[docs]@pytest.mark.django_db
def test_str():
obj = PaymentRun.objects.create_payment_run()
value = str(obj)
assert "Payment Run" in value
assert str(obj.pk) in value
assert "created" in value