Source code for example_checkout.tests.test_object_payment_plan

# -*- encoding: utf-8 -*-
import pytest

from datetime import date
from dateutil.relativedelta import relativedelta
from decimal import Decimal
from unittest import mock

from django.db import transaction

from checkout.models import (
    CheckoutError,
    CheckoutState,
    Customer,
    ObjectPaymentPlan,
)
from checkout.tests.factories import (
    CustomerFactory,
    ObjectPaymentPlanFactory,
    ObjectPaymentPlanInstalmentFactory,
    PaymentPlanFactory,
)
from mail.models import Message
from mail.tests.factories import MailTemplateFactory
from .factories import SalesLedgerFactory


[docs]@pytest.mark.django_db def test_factory(): ObjectPaymentPlanFactory(content_object=SalesLedgerFactory())
[docs]@pytest.mark.django_db def test_str(): str(ObjectPaymentPlanFactory(content_object=SalesLedgerFactory()))
[docs]@pytest.mark.django_db def test_create_object_payment_plan(): sl = SalesLedgerFactory() payment_plan = PaymentPlanFactory(deposit=20, count=2, interval=1) # create the contact plan with the deposit with transaction.atomic(): # this must be run within a transaction ObjectPaymentPlan.objects.create_object_payment_plan( sl, payment_plan, Decimal("100") ) object_payment_plan = ObjectPaymentPlan.objects.for_content_object(sl) # check deposit - count should be '1' and the 'due' date ``today`` result = [(p.count, p.amount, p.due) for p in object_payment_plan.payments] assert [(1, Decimal("20"), date.today())] == result # create the instalments with transaction.atomic(): # this must be run within a transaction object_payment_plan.create_instalments() result = [(p.count, p.amount, p.due) for p in object_payment_plan.payments] offset = 0 # instalments start a month later if after the 15th of the month if date.today().day > 15: offset = 1 assert [ (1, Decimal("20"), date.today()), ( 2, Decimal("40"), date.today() + relativedelta(months=+(1 + offset), day=1), ), ( 3, Decimal("40"), date.today() + relativedelta(months=+(2 + offset), day=1), ), ] == result
[docs]@pytest.mark.django_db def test_create_instalments_once_only(): sl = SalesLedgerFactory() payment_plan = PaymentPlanFactory(deposit=20, count=2, interval=1) # create the contact plan with the deposit with transaction.atomic(): # this must be run within a transaction pp = ObjectPaymentPlan.objects.create_object_payment_plan( sl, payment_plan, Decimal("100") ) # create the instalments with transaction.atomic(): # this must be run within a transaction pp.create_instalments() with pytest.raises(CheckoutError) as e: pp.create_instalments() assert "instalments already created" in str(e.value)
[docs]@pytest.mark.django_db def test_create_instalments_no_deposit(): obj = ObjectPaymentPlanFactory(content_object=SalesLedgerFactory()) with pytest.raises(CheckoutError) as e: obj.create_instalments() assert "no deposit/instalment record" in str(e.value)
[docs]@pytest.mark.django_db def test_create_instalments_corrupt(): object_payment_plan = ObjectPaymentPlanFactory( content_object=SalesLedgerFactory() ) obj = ObjectPaymentPlanInstalmentFactory( object_payment_plan=object_payment_plan, count=2 ) with pytest.raises(CheckoutError) as e: obj.object_payment_plan.create_instalments() assert "no deposit record" in str(e.value)
[docs]@pytest.mark.django_db def test_delete(): obj = ObjectPaymentPlanFactory(content_object=SalesLedgerFactory()) assert obj.deleted is False obj.delete() obj.refresh_from_db() assert obj.deleted is True
[docs]@pytest.mark.django_db def test_fail_or_request(): """Payment plans which have an instalment in the fail or request state.""" p1 = ObjectPaymentPlanFactory(content_object=SalesLedgerFactory()) i1 = ObjectPaymentPlanInstalmentFactory( object_payment_plan=p1, due=date.today() + relativedelta(months=-2), state=CheckoutState.objects.fail, ) p2 = ObjectPaymentPlanFactory(content_object=SalesLedgerFactory()) i2 = ObjectPaymentPlanInstalmentFactory( object_payment_plan=p2, due=date.today() + relativedelta(months=-1), state=CheckoutState.objects.request, ) p3 = ObjectPaymentPlanFactory(content_object=SalesLedgerFactory()) ObjectPaymentPlanInstalmentFactory( object_payment_plan=p3, due=date.today() + relativedelta(months=-1), state=CheckoutState.objects.pending, ) result = ObjectPaymentPlan.objects.fail_or_request assert [i1.pk, i2.pk] == [obj.pk for obj in result]
[docs]@pytest.mark.django_db def test_fail_or_request_duplicate(): """Payment plans which have an instalment in the fail or request state.""" obj = ObjectPaymentPlanFactory(content_object=SalesLedgerFactory()) ObjectPaymentPlanInstalmentFactory( object_payment_plan=obj, due=date.today() + relativedelta(months=-2), state=CheckoutState.objects.fail, ) ObjectPaymentPlanInstalmentFactory( object_payment_plan=obj, due=date.today() + relativedelta(months=-1), state=CheckoutState.objects.request, ) result = ObjectPaymentPlan.objects.fail_or_request assert [obj.pk] == [obj.pk for obj in result]
[docs]@pytest.mark.django_db def test_instalment_count(): """See ``payment_count``.""" obj = ObjectPaymentPlanFactory(content_object=SalesLedgerFactory()) today = date.today() ObjectPaymentPlanInstalmentFactory( object_payment_plan=obj, deposit=True, due=today + relativedelta(days=1), count=1, ) ObjectPaymentPlanInstalmentFactory( object_payment_plan=obj, due=today + relativedelta(days=2), count=2 ) assert 1 == obj.instalment_count
[docs]@pytest.mark.parametrize( "state", [CheckoutState.FAIL, CheckoutState.PENDING, CheckoutState.REQUEST] ) @pytest.mark.django_db def test_instalments_due(state): today = date.today() checkout_state = CheckoutState.objects.get(slug=state) object_payment_plan = ObjectPaymentPlanFactory( content_object=SalesLedgerFactory() ) ObjectPaymentPlanInstalmentFactory( object_payment_plan=object_payment_plan, deposit=True, due=today + relativedelta(days=-30), count=1, ) ObjectPaymentPlanInstalmentFactory( object_payment_plan=object_payment_plan, due=today + relativedelta(days=-15), state=checkout_state, count=2, ) ObjectPaymentPlanInstalmentFactory( object_payment_plan=object_payment_plan, due=today, count=3 ) ObjectPaymentPlanInstalmentFactory( object_payment_plan=object_payment_plan, due=today + relativedelta(days=+30), count=4, ) assert [1, 2] == [x.count for x in object_payment_plan.instalments_due()]
[docs]@pytest.mark.parametrize( "state", [CheckoutState.FAIL, CheckoutState.PENDING, CheckoutState.REQUEST] ) @pytest.mark.django_db def test_instalments_due_exclude_by_due_date(state): today = date.today() checkout_state = CheckoutState.objects.get(slug=state) object_payment_plan = ObjectPaymentPlanFactory( content_object=SalesLedgerFactory() ) ObjectPaymentPlanInstalmentFactory( object_payment_plan=object_payment_plan, deposit=True, due=today + relativedelta(days=-30), count=1, ) obj = ObjectPaymentPlanInstalmentFactory( object_payment_plan=object_payment_plan, due=today + relativedelta(days=-15), state=checkout_state, count=2, ) ObjectPaymentPlanInstalmentFactory( object_payment_plan=object_payment_plan, due=today, count=3 ) ObjectPaymentPlanInstalmentFactory( object_payment_plan=object_payment_plan, due=today + relativedelta(days=+30), count=4, ) qs = object_payment_plan.instalments_due(obj.due) assert [1] == [x.count for x in qs]
[docs]@pytest.mark.django_db def test_outstanding_payment_plans(): assert 0 == ObjectPaymentPlan.objects.outstanding_payment_plans.count()
[docs]@pytest.mark.django_db def test_outstanding_payment_plans_exclude_deleted(): obj = ObjectPaymentPlanFactory( content_object=SalesLedgerFactory(), deleted=True ) ObjectPaymentPlanInstalmentFactory(object_payment_plan=obj) ObjectPaymentPlanInstalmentFactory( object_payment_plan=ObjectPaymentPlanFactory( content_object=SalesLedgerFactory() ) ) assert 1 == ObjectPaymentPlan.objects.outstanding_payment_plans.count()
[docs]@pytest.mark.django_db def test_outstanding_payment_plans_exclude_success(): ObjectPaymentPlanInstalmentFactory( object_payment_plan=ObjectPaymentPlanFactory( content_object=SalesLedgerFactory() ) ) ObjectPaymentPlanInstalmentFactory( state=CheckoutState.objects.success, object_payment_plan=ObjectPaymentPlanFactory( content_object=SalesLedgerFactory() ), ) assert 1 == ObjectPaymentPlan.objects.outstanding_payment_plans.count()
[docs]@pytest.mark.django_db def test_outstanding_payment_plans_filter_two(): obj = ObjectPaymentPlanFactory(content_object=SalesLedgerFactory()) ObjectPaymentPlanInstalmentFactory(object_payment_plan=obj) ObjectPaymentPlanInstalmentFactory( object_payment_plan=obj, due=date.today() + relativedelta(months=+1) ) assert 1 == ObjectPaymentPlan.objects.outstanding_payment_plans.count()
[docs]@pytest.mark.django_db def test_payment_count(): """See ``instalment_count``.""" obj = ObjectPaymentPlanFactory(content_object=SalesLedgerFactory()) ObjectPaymentPlanInstalmentFactory( object_payment_plan=obj, deposit=True, due=date.today() + relativedelta(days=1), count=1, ) ObjectPaymentPlanInstalmentFactory( object_payment_plan=obj, due=date.today() + relativedelta(days=2), count=2, ) assert 2 == obj.payment_count
[docs]@pytest.mark.django_db def test_refresh_card_expiry_dates(): MailTemplateFactory(slug=Customer.MAIL_TEMPLATE_CARD_EXPIRY) with mock.patch("stripe.Customer.retrieve") as mock_retrieve: mock_retrieve.return_value = { "default_source": "1234", "sources": { "data": [{"id": "1234", "exp_month": "8", "exp_year": "1986"}] }, } obj = ObjectPaymentPlanFactory(content_object=SalesLedgerFactory()) ObjectPaymentPlanInstalmentFactory(object_payment_plan=obj) ObjectPaymentPlanInstalmentFactory( object_payment_plan=obj, due=date.today() + relativedelta(months=+1) ) customer = CustomerFactory(email=obj.content_object.checkout_email) ObjectPaymentPlan.objects.refresh_card_expiry_dates() customer.refresh_from_db() assert customer.refresh is True # check email template context assert 1 == Message.objects.count() message = Message.objects.first() assert 1 == message.mail_set.count() mail = message.mail_set.first() assert 1 == mail.mailfield_set.count() assert {"name": customer.name} == { f.key: f.value for f in mail.mailfield_set.all() }
[docs]@pytest.mark.django_db def test_refresh_card_expiry_dates_future(): with mock.patch("stripe.Customer.retrieve") as mock_retrieve: mock_retrieve.return_value = { "default_source": "1234", "sources": { "data": [{"id": "1234", "exp_month": "8", "exp_year": "2050"}] }, } obj = ObjectPaymentPlanFactory(content_object=SalesLedgerFactory()) ObjectPaymentPlanInstalmentFactory(object_payment_plan=obj) ObjectPaymentPlanInstalmentFactory( object_payment_plan=obj, due=date.today() + relativedelta(months=+1) ) customer = CustomerFactory(email=obj.content_object.checkout_email) ObjectPaymentPlan.objects.refresh_card_expiry_dates() customer.refresh_from_db() assert customer.refresh is False # check we didn't send a notification email assert 0 == Message.objects.count()
[docs]@pytest.mark.django_db def test_refresh_card_expiry_dates_refreshed(): """Customer card already marked for 'refresh', so don't send an email.""" with mock.patch("stripe.Customer.retrieve") as mock_retrieve: mock_retrieve.return_value = { "default_source": "1234", "sources": { "data": [{"id": "1234", "exp_month": "8", "exp_year": "1986"}] }, } obj = ObjectPaymentPlanFactory(content_object=SalesLedgerFactory()) ObjectPaymentPlanInstalmentFactory(object_payment_plan=obj) ObjectPaymentPlanInstalmentFactory( object_payment_plan=obj, due=date.today() + relativedelta(months=+1) ) customer = CustomerFactory( email=obj.content_object.checkout_email, refresh=True ) ObjectPaymentPlan.objects.refresh_card_expiry_dates() customer.refresh_from_db() assert customer.refresh is True # check we didn't send a notification email assert 0 == Message.objects.count()
[docs]@pytest.mark.django_db def test_report_card_expiry_dates(): object_payment_plan = ObjectPaymentPlanFactory( content_object=SalesLedgerFactory() ) ObjectPaymentPlanInstalmentFactory(object_payment_plan=object_payment_plan) obj = ObjectPaymentPlanInstalmentFactory( object_payment_plan=ObjectPaymentPlanFactory( content_object=SalesLedgerFactory() ) ) CustomerFactory(email=obj.object_payment_plan.content_object.checkout_email) ObjectPaymentPlan.objects.report_card_expiry_dates