Stripe checkout #104411
@ -152,7 +152,9 @@ def _on_subscription_expired(sender: looper.models.Subscription, **kwargs):
|
|||||||
assert sender.status == 'expired', f'Expected expired, got "{sender.status} (pk={sender.pk})"'
|
assert sender.status == 'expired', f'Expected expired, got "{sender.status} (pk={sender.pk})"'
|
||||||
|
|
||||||
# Only send a "subscription expired" email when there are no other active subscriptions
|
# Only send a "subscription expired" email when there are no other active subscriptions
|
||||||
if not queries.has_active_subscription(sender.user):
|
customer = sender.customer
|
||||||
|
user = customer.user
|
||||||
|
if user and not queries.has_active_subscription(user):
|
||||||
tasks.send_mail_subscription_expired(subscription_id=sender.pk)
|
tasks.send_mail_subscription_expired(subscription_id=sender.pk)
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,8 +44,9 @@ def _construct_subscription_mail(mail_name: str, context: Dict[str, Any]) -> Tup
|
|||||||
def send_mail_bank_transfer_required(subscription_id: int):
|
def send_mail_bank_transfer_required(subscription_id: int):
|
||||||
"""Send out an email notifying about the required bank transfer payment."""
|
"""Send out an email notifying about the required bank transfer payment."""
|
||||||
subscription = looper.models.Subscription.objects.get(pk=subscription_id)
|
subscription = looper.models.Subscription.objects.get(pk=subscription_id)
|
||||||
user = subscription.user
|
customer = subscription.customer
|
||||||
email = user.customer.billing_address.email or user.email
|
user = customer.user
|
||||||
|
email = customer.billing_address.email or user.email
|
||||||
assert (
|
assert (
|
||||||
email
|
email
|
||||||
), f'Cannot send notification about bank payment for subscription {subscription.pk}: no email'
|
), f'Cannot send notification about bank payment for subscription {subscription.pk}: no email'
|
||||||
@ -65,7 +66,7 @@ def send_mail_bank_transfer_required(subscription_id: int):
|
|||||||
assert order, "Can't send a notificaton about bank transfer without an existing order"
|
assert order, "Can't send a notificaton about bank transfer without an existing order"
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'user': subscription.user,
|
'user': user,
|
||||||
'subscription': subscription,
|
'subscription': subscription,
|
||||||
'order': order,
|
'order': order,
|
||||||
**get_template_context(),
|
**get_template_context(),
|
||||||
@ -134,8 +135,8 @@ def send_mail_automatic_payment_performed(order_id: int, transaction_id: int):
|
|||||||
"""Send out an email notifying about the soft-failed payment."""
|
"""Send out an email notifying about the soft-failed payment."""
|
||||||
order = looper.models.Order.objects.get(pk=order_id)
|
order = looper.models.Order.objects.get(pk=order_id)
|
||||||
transaction = looper.models.Transaction.objects.get(pk=transaction_id)
|
transaction = looper.models.Transaction.objects.get(pk=transaction_id)
|
||||||
user = order.user
|
customer = order.customer
|
||||||
customer = user.customer
|
user = customer.user
|
||||||
email = customer.billing_address.email or user.email
|
email = customer.billing_address.email or user.email
|
||||||
logger.debug('Sending %r notification to %s', order.status, email)
|
logger.debug('Sending %r notification to %s', order.status, email)
|
||||||
|
|
||||||
@ -149,7 +150,7 @@ def send_mail_automatic_payment_performed(order_id: int, transaction_id: int):
|
|||||||
receipt_url = absolute_url('subscriptions:receipt', kwargs={'order_id': order.pk})
|
receipt_url = absolute_url('subscriptions:receipt', kwargs={'order_id': order.pk})
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'user': subscription.user,
|
'user': user,
|
||||||
'email': email,
|
'email': email,
|
||||||
'order': order,
|
'order': order,
|
||||||
'subscription': subscription,
|
'subscription': subscription,
|
||||||
@ -186,7 +187,8 @@ def send_mail_managed_subscription_notification(subscription_id: int):
|
|||||||
subscription.pk,
|
subscription.pk,
|
||||||
)
|
)
|
||||||
|
|
||||||
user = subscription.user
|
customer = subscription.customer
|
||||||
|
user = customer.user
|
||||||
admin_url = absolute_url(
|
admin_url = absolute_url(
|
||||||
'admin:looper_subscription_change',
|
'admin:looper_subscription_change',
|
||||||
kwargs={'object_id': subscription.id},
|
kwargs={'object_id': subscription.id},
|
||||||
@ -221,7 +223,8 @@ def send_mail_managed_subscription_notification(subscription_id: int):
|
|||||||
def send_mail_subscription_expired(subscription_id: int):
|
def send_mail_subscription_expired(subscription_id: int):
|
||||||
"""Send out an email notifying about an expired subscription."""
|
"""Send out an email notifying about an expired subscription."""
|
||||||
subscription = looper.models.Subscription.objects.get(pk=subscription_id)
|
subscription = looper.models.Subscription.objects.get(pk=subscription_id)
|
||||||
user = subscription.user
|
customer = subscription.customer
|
||||||
|
user = customer.user
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
subscription.status == 'expired'
|
subscription.status == 'expired'
|
||||||
@ -230,7 +233,7 @@ def send_mail_subscription_expired(subscription_id: int):
|
|||||||
if queries.has_active_subscription(user):
|
if queries.has_active_subscription(user):
|
||||||
logger.error(
|
logger.error(
|
||||||
'Not sending subscription-expired notification: pk=%s has other active subscriptions',
|
'Not sending subscription-expired notification: pk=%s has other active subscriptions',
|
||||||
subscription.user_id,
|
user.pk,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -249,7 +252,7 @@ def send_mail_subscription_expired(subscription_id: int):
|
|||||||
|
|
||||||
logger.debug('Sending subscription-expired notification to %s', email)
|
logger.debug('Sending subscription-expired notification to %s', email)
|
||||||
context = {
|
context = {
|
||||||
'user': subscription.user,
|
'user': user,
|
||||||
'subscription': subscription,
|
'subscription': subscription,
|
||||||
'latest_trainings': get_latest_trainings_and_production_lessons(),
|
'latest_trainings': get_latest_trainings_and_production_lessons(),
|
||||||
'latest_posts': Post.objects.filter(is_published=True)[:5],
|
'latest_posts': Post.objects.filter(is_published=True)[:5],
|
||||||
@ -281,8 +284,8 @@ def send_mail_no_payment_method(order_id: int):
|
|||||||
), 'send_mail_no_payment_method expects automatic subscription'
|
), 'send_mail_no_payment_method expects automatic subscription'
|
||||||
assert 'fail' in order.status, f'Unexpected order pk={order_id} status: {order.status}'
|
assert 'fail' in order.status, f'Unexpected order pk={order_id} status: {order.status}'
|
||||||
|
|
||||||
user = order.user
|
customer = order.customer
|
||||||
customer = user.customer
|
user = customer.user
|
||||||
email = customer.billing_address.email or user.email
|
email = customer.billing_address.email or user.email
|
||||||
logger.debug('Sending %r notification to %s', order.status, email)
|
logger.debug('Sending %r notification to %s', order.status, email)
|
||||||
|
|
||||||
@ -296,7 +299,7 @@ def send_mail_no_payment_method(order_id: int):
|
|||||||
receipt_url = absolute_url('subscriptions:receipt', kwargs={'order_id': order.pk})
|
receipt_url = absolute_url('subscriptions:receipt', kwargs={'order_id': order.pk})
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'user': subscription.user,
|
'user': user,
|
||||||
'email': email,
|
'email': email,
|
||||||
'order': order,
|
'order': order,
|
||||||
'subscription': subscription,
|
'subscription': subscription,
|
||||||
|
@ -440,7 +440,8 @@ class BaseSubscriptionTestCase(TestCase):
|
|||||||
self.assertIn('Blender Studio Team', email_body)
|
self.assertIn('Blender Studio Team', email_body)
|
||||||
|
|
||||||
def _assert_payment_soft_failed_email_is_sent(self, subscription):
|
def _assert_payment_soft_failed_email_is_sent(self, subscription):
|
||||||
user = subscription.user
|
customer = subscription.customer
|
||||||
|
user = customer.user
|
||||||
self.assertEqual(len(mail.outbox), 1)
|
self.assertEqual(len(mail.outbox), 1)
|
||||||
_write_mail(mail)
|
_write_mail(mail)
|
||||||
email = mail.outbox[0]
|
email = mail.outbox[0]
|
||||||
@ -470,7 +471,8 @@ class BaseSubscriptionTestCase(TestCase):
|
|||||||
self.assertIn('Blender Studio Team', email_body)
|
self.assertIn('Blender Studio Team', email_body)
|
||||||
|
|
||||||
def _assert_payment_failed_email_is_sent(self, subscription):
|
def _assert_payment_failed_email_is_sent(self, subscription):
|
||||||
user = subscription.user
|
customer = subscription.customer
|
||||||
|
user = customer.user
|
||||||
self.assertEqual(len(mail.outbox), 1)
|
self.assertEqual(len(mail.outbox), 1)
|
||||||
_write_mail(mail)
|
_write_mail(mail)
|
||||||
email = mail.outbox[0]
|
email = mail.outbox[0]
|
||||||
@ -497,7 +499,8 @@ class BaseSubscriptionTestCase(TestCase):
|
|||||||
self.assertIn('Blender Studio Team', email_body)
|
self.assertIn('Blender Studio Team', email_body)
|
||||||
|
|
||||||
def _assert_payment_paid_email_is_sent(self, subscription):
|
def _assert_payment_paid_email_is_sent(self, subscription):
|
||||||
user = subscription.user
|
customer = subscription.customer
|
||||||
|
user = customer.user
|
||||||
self.assertEqual(len(mail.outbox), 1)
|
self.assertEqual(len(mail.outbox), 1)
|
||||||
_write_mail(mail)
|
_write_mail(mail)
|
||||||
email = mail.outbox[0]
|
email = mail.outbox[0]
|
||||||
@ -523,7 +526,8 @@ class BaseSubscriptionTestCase(TestCase):
|
|||||||
self.assertIn('Blender Studio Team', email_body)
|
self.assertIn('Blender Studio Team', email_body)
|
||||||
|
|
||||||
def _assert_managed_subscription_notification_email_is_sent(self, subscription):
|
def _assert_managed_subscription_notification_email_is_sent(self, subscription):
|
||||||
user = subscription.user
|
customer = subscription.customer
|
||||||
|
user = customer.user
|
||||||
self.assertEqual(len(mail.outbox), 1)
|
self.assertEqual(len(mail.outbox), 1)
|
||||||
_write_mail(mail)
|
_write_mail(mail)
|
||||||
email = mail.outbox[0]
|
email = mail.outbox[0]
|
||||||
@ -542,11 +546,12 @@ class BaseSubscriptionTestCase(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _assert_subscription_expired_email_is_sent(self, subscription):
|
def _assert_subscription_expired_email_is_sent(self, subscription):
|
||||||
user = subscription.user
|
customer = subscription.customer
|
||||||
|
user = customer.user
|
||||||
self.assertEqual(len(mail.outbox), 1)
|
self.assertEqual(len(mail.outbox), 1)
|
||||||
_write_mail(mail)
|
_write_mail(mail)
|
||||||
email = mail.outbox[0]
|
email = mail.outbox[0]
|
||||||
self.assertEqual(email.to, [subscription.user.email])
|
self.assertEqual(email.to, [user.email])
|
||||||
self.assertEqual(email.from_email, 'webmaster@localhost')
|
self.assertEqual(email.from_email, 'webmaster@localhost')
|
||||||
self.assertEqual(email.subject, 'We miss you at Blender Studio')
|
self.assertEqual(email.subject, 'We miss you at Blender Studio')
|
||||||
self.assertEqual(email.alternatives[0][1], 'text/html')
|
self.assertEqual(email.alternatives[0][1], 'text/html')
|
||||||
|
@ -17,18 +17,20 @@ from subscriptions.tests.base import BaseSubscriptionTestCase
|
|||||||
import subscriptions.tasks
|
import subscriptions.tasks
|
||||||
import users.tasks
|
import users.tasks
|
||||||
import users.tests.util as util
|
import users.tests.util as util
|
||||||
|
from common.tests.factories.users import OAuthUserInfoFactory
|
||||||
|
|
||||||
|
|
||||||
class TestClock(BaseSubscriptionTestCase):
|
class TestClockBraintree(BaseSubscriptionTestCase):
|
||||||
def _create_subscription_due_now(self) -> Subscription:
|
def _create_subscription_due_now(self) -> Subscription:
|
||||||
user = create_customer_with_billing_address(country='NL', full_name='Jane Doe')
|
customer = create_customer_with_billing_address(country='NL', full_name='Jane Doe')
|
||||||
|
OAuthUserInfoFactory(user=customer.user, oauth_user_id=554433)
|
||||||
now = timezone.now()
|
now = timezone.now()
|
||||||
with mock.patch('django.utils.timezone.now') as mock_now:
|
with mock.patch('django.utils.timezone.now') as mock_now:
|
||||||
mock_now.return_value = now + relativedelta(months=-1)
|
mock_now.return_value = now + relativedelta(months=-1)
|
||||||
# print('fake now:', mock_now.return_value)
|
# print('fake now:', mock_now.return_value)
|
||||||
subscription = SubscriptionFactory(
|
subscription = SubscriptionFactory(
|
||||||
user=user,
|
customer=customer,
|
||||||
payment_method__customer_id=user.customer.pk,
|
payment_method__customer_id=customer.pk,
|
||||||
payment_method__recognisable_name='Test payment method',
|
payment_method__recognisable_name='Test payment method',
|
||||||
payment_method__gateway=Gateway.objects.get(name='braintree'),
|
payment_method__gateway=Gateway.objects.get(name='braintree'),
|
||||||
currency='USD',
|
currency='USD',
|
||||||
@ -111,7 +113,7 @@ class TestClock(BaseSubscriptionTestCase):
|
|||||||
|
|
||||||
# Tick the clock and check that order and transaction were created
|
# Tick the clock and check that order and transaction were created
|
||||||
util.mock_blender_id_badger_badger_response(
|
util.mock_blender_id_badger_badger_response(
|
||||||
'revoke', 'cloud_subscriber', self.subscription.user.oauth_info.oauth_user_id
|
'revoke', 'cloud_subscriber', self.subscription.customer.user.oauth_info.oauth_user_id
|
||||||
)
|
)
|
||||||
Clock().tick()
|
Clock().tick()
|
||||||
|
|
||||||
@ -164,7 +166,7 @@ class TestClock(BaseSubscriptionTestCase):
|
|||||||
|
|
||||||
# Create another active subscription for the same user
|
# Create another active subscription for the same user
|
||||||
SubscriptionFactory(
|
SubscriptionFactory(
|
||||||
user=self.subscription.user,
|
customer=self.subscription.customer,
|
||||||
payment_method=self.subscription.payment_method,
|
payment_method=self.subscription.payment_method,
|
||||||
currency='USD',
|
currency='USD',
|
||||||
price=Money('USD', 1110),
|
price=Money('USD', 1110),
|
||||||
@ -187,10 +189,12 @@ class TestClock(BaseSubscriptionTestCase):
|
|||||||
)
|
)
|
||||||
def test_automated_payment_paid_email_is_sent(self):
|
def test_automated_payment_paid_email_is_sent(self):
|
||||||
now = timezone.now()
|
now = timezone.now()
|
||||||
|
self.assertEqual(self.subscription.collection_method, 'automatic')
|
||||||
|
|
||||||
# Tick the clock and check that subscription renews, order and transaction were created
|
# Tick the clock and check that subscription renews, order and transaction were created
|
||||||
with patch(
|
with patch(
|
||||||
'looper.gateways.BraintreeGateway.transact_sale', return_value='mock-transaction-id'
|
'looper.gateways.BraintreeGateway.transact_sale',
|
||||||
|
return_value={'transaction_id': 'mock-transaction-id'},
|
||||||
):
|
):
|
||||||
Clock().tick()
|
Clock().tick()
|
||||||
|
|
||||||
@ -251,9 +255,9 @@ class TestClock(BaseSubscriptionTestCase):
|
|||||||
class TestClockExpiredSubscription(BaseSubscriptionTestCase):
|
class TestClockExpiredSubscription(BaseSubscriptionTestCase):
|
||||||
def test_subscription_on_hold_not_long_enough(self):
|
def test_subscription_on_hold_not_long_enough(self):
|
||||||
now = timezone.now()
|
now = timezone.now()
|
||||||
user = create_customer_with_billing_address(country='NL', full_name='Jane Doe')
|
customer = create_customer_with_billing_address(country='NL', full_name='Jane Doe')
|
||||||
self.subscription = SubscriptionFactory(
|
self.subscription = SubscriptionFactory(
|
||||||
user=user,
|
customer=customer,
|
||||||
status='on-hold',
|
status='on-hold',
|
||||||
# payment date has passed, but not long enough ago
|
# payment date has passed, but not long enough ago
|
||||||
next_payment=now - timedelta(weeks=4),
|
next_payment=now - timedelta(weeks=4),
|
||||||
@ -280,15 +284,16 @@ class TestClockExpiredSubscription(BaseSubscriptionTestCase):
|
|||||||
@responses.activate
|
@responses.activate
|
||||||
def test_subscription_on_hold_too_long_status_changed_to_expired_email_sent(self):
|
def test_subscription_on_hold_too_long_status_changed_to_expired_email_sent(self):
|
||||||
now = timezone.now()
|
now = timezone.now()
|
||||||
user = create_customer_with_billing_address(country='NL', full_name='Jane Doe')
|
customer = create_customer_with_billing_address(country='NL', full_name='Jane Doe')
|
||||||
|
OAuthUserInfoFactory(user=customer.user, oauth_user_id=223344)
|
||||||
self.subscription = SubscriptionFactory(
|
self.subscription = SubscriptionFactory(
|
||||||
user=user,
|
customer=customer,
|
||||||
status='on-hold',
|
status='on-hold',
|
||||||
# payment date has passed a long long time ago
|
# payment date has passed a long long time ago
|
||||||
next_payment=now - timedelta(weeks=4 * 10),
|
next_payment=now - timedelta(weeks=4 * 10),
|
||||||
)
|
)
|
||||||
util.mock_blender_id_badger_badger_response(
|
util.mock_blender_id_badger_badger_response(
|
||||||
'revoke', 'cloud_subscriber', user.oauth_info.oauth_user_id
|
'revoke', 'cloud_subscriber', customer.user.oauth_info.oauth_user_id
|
||||||
)
|
)
|
||||||
|
|
||||||
Clock().tick()
|
Clock().tick()
|
||||||
|
Loading…
Reference in New Issue
Block a user