Stripe checkout #104411

Merged
Anna Sirota merged 61 commits from stripe into main 2024-06-17 18:08:41 +02:00
13 changed files with 169 additions and 114 deletions
Showing only changes of commit 7ed078259f - Show all commits

View File

@ -162,11 +162,16 @@ class PaymentForm(BillingAddressForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
"""Pre-fill additional initial data from request.""" """Pre-fill additional initial data from request."""
self.request = kwargs.pop('request') self.request = kwargs.pop('request', None)
self.customer = self.request.user.customer
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self._set_initial_from_request()
def _set_initial_from_request(self):
if not self.request:
return
# Only preset country when it's not already selected by the customer # Only preset country when it's not already selected by the customer
geoip_country = self.request.session.get(COUNTRY_CODE_SESSION_KEY) geoip_country = self.request.session.get(COUNTRY_CODE_SESSION_KEY)
if geoip_country and (not self.instance.country): if geoip_country and (not self.instance.country):

View File

@ -90,7 +90,7 @@ class Team(mixins.CreatedUpdatedMixin, models.Model):
"""Add given user to the team.""" """Add given user to the team."""
seats_taken = self.users.count() seats_taken = self.users.count()
# Not adding the team manager to the team # Not adding the team manager to the team
if user.pk == self.subscription.user_id: if user.pk == self.subscription.customer.user_id:
return return
if self.seats is not None and seats_taken >= self.seats: if self.seats is not None and seats_taken >= self.seats:
logger.warning( logger.warning(

View File

@ -1,6 +1,5 @@
import os import os
from django.contrib.auth import get_user_model
from django.core import mail from django.core import mail
from django.db.models import signals from django.db.models import signals
from django.test import TestCase from django.test import TestCase
@ -11,8 +10,6 @@ import responses
from looper.tests.factories import create_customer_with_billing_address from looper.tests.factories import create_customer_with_billing_address
import users.tests.util as util import users.tests.util as util
User = get_user_model()
def _write_mail(mail, index=0): def _write_mail(mail, index=0):
email = mail.outbox[index] email = mail.outbox[index]

View File

@ -213,10 +213,7 @@ class TestBillingAddressForm(BaseSubscriptionTestCase):
class TestPaymentForm(BaseSubscriptionTestCase): class TestPaymentForm(BaseSubscriptionTestCase):
required_payment_form_data = { required_payment_form_data = {
'gateway': 'bank',
'payment_method_nonce': 'fake-nonce',
'plan_variation_id': 1, 'plan_variation_id': 1,
'price': '9.90',
} }
def test_instance_loads_both_address_and_customer_data(self): def test_instance_loads_both_address_and_customer_data(self):
@ -243,9 +240,6 @@ class TestPaymentForm(BaseSubscriptionTestCase):
'country': ['This field is required.'], 'country': ['This field is required.'],
'email': ['This field is required.'], 'email': ['This field is required.'],
'full_name': ['This field is required.'], 'full_name': ['This field is required.'],
'gateway': ['This field is required.'],
'payment_method_nonce': ['This field is required.'],
'price': ['This field is required.'],
}, },
) )

View File

@ -23,25 +23,27 @@ class TestHasActiveSubscription(TestCase):
def test_true_when_subscription_active(self): def test_true_when_subscription_active(self):
subscription = SubscriptionFactory( subscription = SubscriptionFactory(
customer=UserFactory().customer,
plan_id=1, plan_id=1,
status=list(looper.models.Subscription._ACTIVE_STATUSES)[0], status=list(looper.models.Subscription._ACTIVE_STATUSES)[0],
) )
self.assertTrue(has_active_subscription(subscription.user)) self.assertTrue(has_active_subscription(subscription.customer.user))
def test_false_when_subscription_inactive(self): def test_false_when_subscription_inactive(self):
subscription = SubscriptionFactory(plan_id=1) subscription = SubscriptionFactory(customer=UserFactory().customer, plan_id=1)
self.assertFalse(has_active_subscription(subscription.user)) self.assertFalse(has_active_subscription(subscription.customer.user))
def test_false_when_team_subscription_inactive(self): def test_false_when_team_subscription_inactive(self):
team = TeamFactory(subscription__plan_id=1) team = TeamFactory(subscription__customer=UserFactory().customer, subscription__plan_id=1)
team.team_users.create(user=UserFactory()) team.team_users.create(user=UserFactory())
self.assertFalse(has_active_subscription(team.team_users.first().user)) self.assertFalse(has_active_subscription(team.team_users.first().user))
def test_true_when_team_subscription_active(self): def test_true_when_team_subscription_active(self):
team = TeamFactory( team = TeamFactory(
subscription__customer=UserFactory().customer,
subscription__plan_id=1, subscription__plan_id=1,
subscription__status=list(looper.models.Subscription._ACTIVE_STATUSES)[0], subscription__status=list(looper.models.Subscription._ACTIVE_STATUSES)[0],
) )
@ -58,30 +60,34 @@ class TestHasNotYetCancelledSubscription(TestCase):
def test_true_when_subscription_active(self): def test_true_when_subscription_active(self):
subscription = SubscriptionFactory( subscription = SubscriptionFactory(
customer=UserFactory().customer,
plan_id=1, plan_id=1,
status=list(looper.models.Subscription._ACTIVE_STATUSES)[0], status=list(looper.models.Subscription._ACTIVE_STATUSES)[0],
) )
self.assertTrue(has_not_yet_cancelled_subscription(subscription.user)) self.assertTrue(has_not_yet_cancelled_subscription(subscription.customer.user))
def test_false_when_subscription_cancelled(self): def test_false_when_subscription_cancelled(self):
subscription = SubscriptionFactory(plan_id=1, status='cancelled') subscription = SubscriptionFactory(
customer=UserFactory().customer, plan_id=1, status='cancelled'
)
self.assertFalse(has_not_yet_cancelled_subscription(subscription.user)) self.assertFalse(has_not_yet_cancelled_subscription(subscription.customer.user))
def test_true_when_subscription_inactive(self): def test_true_when_subscription_inactive(self):
subscription = SubscriptionFactory(plan_id=1) subscription = SubscriptionFactory(customer=UserFactory().customer, plan_id=1)
self.assertTrue(has_not_yet_cancelled_subscription(subscription.user)) self.assertTrue(has_not_yet_cancelled_subscription(subscription.customer.user))
def test_false_when_team_subscription_inactive(self): def test_false_when_team_subscription_inactive(self):
team = TeamFactory(subscription__plan_id=1) team = TeamFactory(subscription__customer=UserFactory().customer, subscription__plan_id=1)
team.team_users.create(user=UserFactory()) team.team_users.create(user=UserFactory())
self.assertFalse(has_not_yet_cancelled_subscription(team.team_users.first().user)) self.assertFalse(has_not_yet_cancelled_subscription(team.team_users.first().user))
def test_false_when_team_subscription_active(self): def test_false_when_team_subscription_active(self):
team = TeamFactory( team = TeamFactory(
subscription__customer=UserFactory().customer,
subscription__plan_id=1, subscription__plan_id=1,
subscription__status=list(looper.models.Subscription._ACTIVE_STATUSES)[0], subscription__status=list(looper.models.Subscription._ACTIVE_STATUSES)[0],
) )
@ -91,6 +97,7 @@ class TestHasNotYetCancelledSubscription(TestCase):
def test_false_when_team_subscription_cancelled(self): def test_false_when_team_subscription_cancelled(self):
team = TeamFactory( team = TeamFactory(
subscription__customer=UserFactory().customer,
subscription__plan_id=1, subscription__plan_id=1,
subscription__status='cancelled', subscription__status='cancelled',
) )
@ -100,12 +107,13 @@ class TestHasNotYetCancelledSubscription(TestCase):
def test_true_when_team_subscription_cancelled_personal_active(self): def test_true_when_team_subscription_cancelled_personal_active(self):
team = TeamFactory( team = TeamFactory(
subscription__customer=UserFactory().customer,
subscription__plan_id=1, subscription__plan_id=1,
subscription__status='cancelled', subscription__status='cancelled',
) )
team.team_users.create(user=UserFactory()) team.team_users.create(user=UserFactory())
SubscriptionFactory( SubscriptionFactory(
user=team.team_users.first().user, customer=team.team_users.first().user.customer,
plan_id=1, plan_id=1,
status=list(looper.models.Subscription._ACTIVE_STATUSES)[0], status=list(looper.models.Subscription._ACTIVE_STATUSES)[0],
) )
@ -114,12 +122,13 @@ class TestHasNotYetCancelledSubscription(TestCase):
def test_false_when_team_subscription_active_personal_cancelled(self): def test_false_when_team_subscription_active_personal_cancelled(self):
team = TeamFactory( team = TeamFactory(
subscription__customer=UserFactory().customer,
subscription__plan_id=1, subscription__plan_id=1,
subscription__status=list(looper.models.Subscription._ACTIVE_STATUSES)[0], subscription__status=list(looper.models.Subscription._ACTIVE_STATUSES)[0],
) )
team.team_users.create(user=UserFactory()) team.team_users.create(user=UserFactory())
SubscriptionFactory( SubscriptionFactory(
user=team.team_users.first().user, customer=team.team_users.first().user.customer,
plan_id=1, plan_id=1,
status='cancelled', status='cancelled',
) )
@ -135,25 +144,27 @@ class TestHasSubscription(TestCase):
def test_true_when_subscription_active(self): def test_true_when_subscription_active(self):
subscription = SubscriptionFactory( subscription = SubscriptionFactory(
customer=UserFactory().customer,
plan_id=1, plan_id=1,
status=list(looper.models.Subscription._ACTIVE_STATUSES)[0], status=list(looper.models.Subscription._ACTIVE_STATUSES)[0],
) )
self.assertTrue(has_subscription(subscription.user)) self.assertTrue(has_subscription(subscription.customer.user))
def test_true_when_subscription_inactive(self): def test_true_when_subscription_inactive(self):
subscription = SubscriptionFactory(plan_id=1) subscription = SubscriptionFactory(customer=UserFactory().customer, plan_id=1)
self.assertTrue(has_subscription(subscription.user)) self.assertTrue(has_subscription(subscription.customer.user))
def test_true_when_team_subscription_inactive(self): def test_true_when_team_subscription_inactive(self):
team = TeamFactory(subscription__plan_id=1) team = TeamFactory(subscription__customer=UserFactory().customer, subscription__plan_id=1)
team.team_users.create(user=UserFactory()) team.team_users.create(user=UserFactory())
self.assertTrue(has_subscription(team.team_users.first().user)) self.assertTrue(has_subscription(team.team_users.first().user))
def test_true_when_team_subscription_active(self): def test_true_when_team_subscription_active(self):
team = TeamFactory( team = TeamFactory(
subscription__customer=UserFactory().customer,
subscription__plan_id=1, subscription__plan_id=1,
subscription__status=list(looper.models.Subscription._ACTIVE_STATUSES)[0], subscription__status=list(looper.models.Subscription._ACTIVE_STATUSES)[0],
) )
@ -163,20 +174,27 @@ class TestHasSubscription(TestCase):
def test_true_when_subscription_active_is_legacy(self): def test_true_when_subscription_active_is_legacy(self):
subscription = SubscriptionFactory( subscription = SubscriptionFactory(
customer=UserFactory().customer,
plan_id=1, plan_id=1,
status=list(looper.models.Subscription._ACTIVE_STATUSES)[0], status=list(looper.models.Subscription._ACTIVE_STATUSES)[0],
is_legacy=True, is_legacy=True,
) )
self.assertTrue(has_subscription(subscription.user)) self.assertTrue(has_subscription(subscription.customer.user))
def test_true_when_subscription_inactive_and_is_legacy(self): def test_true_when_subscription_inactive_and_is_legacy(self):
subscription = SubscriptionFactory(plan_id=1, is_legacy=True) subscription = SubscriptionFactory(
customer=UserFactory().customer, plan_id=1, is_legacy=True
)
self.assertTrue(has_subscription(subscription.user)) self.assertTrue(has_subscription(subscription.customer.user))
def test_true_when_team_subscription_inactive_and_is_legacy(self): def test_true_when_team_subscription_inactive_and_is_legacy(self):
team = TeamFactory(subscription__plan_id=1, subscription__is_legacy=True) team = TeamFactory(
subscription__customer=UserFactory().customer,
subscription__plan_id=1,
subscription__is_legacy=True,
)
team.team_users.create(user=UserFactory()) team.team_users.create(user=UserFactory())
self.assertTrue(has_subscription(team.team_users.first().user)) self.assertTrue(has_subscription(team.team_users.first().user))
@ -190,45 +208,54 @@ class TestHasNonLegacySubscription(TestCase):
def test_true_when_subscription_active_and_not_is_legacy(self): def test_true_when_subscription_active_and_not_is_legacy(self):
subscription = SubscriptionFactory( subscription = SubscriptionFactory(
customer=UserFactory().customer,
plan_id=1, plan_id=1,
status=list(looper.models.Subscription._ACTIVE_STATUSES)[0], status=list(looper.models.Subscription._ACTIVE_STATUSES)[0],
) )
self.assertTrue(has_non_legacy_subscription(subscription.user)) self.assertTrue(has_non_legacy_subscription(subscription.customer.user))
def test_true_when_subscription_inactive_and_not_is_legacy(self): def test_true_when_subscription_inactive_and_not_is_legacy(self):
subscription = SubscriptionFactory(plan_id=1) subscription = SubscriptionFactory(customer=UserFactory().customer, plan_id=1)
self.assertTrue(has_non_legacy_subscription(subscription.user)) self.assertTrue(has_non_legacy_subscription(subscription.customer.user))
def test_true_when_team_subscription_inactive_and_not_is_legacy(self): def test_true_when_team_subscription_inactive_and_not_is_legacy(self):
team = TeamFactory(subscription__plan_id=1) team = TeamFactory(subscription__customer=UserFactory().customer, subscription__plan_id=1)
team.team_users.create(user=UserFactory()) team.team_users.create(user=UserFactory())
self.assertTrue(has_non_legacy_subscription(team.team_users.first().user)) self.assertTrue(has_non_legacy_subscription(team.team_users.first().user))
def test_false_when_subscription_inactive_and_is_legacy(self): def test_false_when_subscription_inactive_and_is_legacy(self):
subscription = SubscriptionFactory(plan_id=1, is_legacy=True) subscription = SubscriptionFactory(
customer=UserFactory().customer, plan_id=1, is_legacy=True
)
self.assertFalse(has_non_legacy_subscription(subscription.user)) self.assertFalse(has_non_legacy_subscription(subscription.customer.user))
def test_false_when_subscription_active_and_is_legacy(self): def test_false_when_subscription_active_and_is_legacy(self):
subscription = SubscriptionFactory( subscription = SubscriptionFactory(
customer=UserFactory().customer,
plan_id=1, plan_id=1,
status=list(looper.models.Subscription._ACTIVE_STATUSES)[0], status=list(looper.models.Subscription._ACTIVE_STATUSES)[0],
is_legacy=True, is_legacy=True,
) )
self.assertFalse(has_non_legacy_subscription(subscription.user)) self.assertFalse(has_non_legacy_subscription(subscription.customer.user))
def test_false_when_team_subscription_inactive_and_is_legacy(self): def test_false_when_team_subscription_inactive_and_is_legacy(self):
team = TeamFactory(subscription__plan_id=1, subscription__is_legacy=True) team = TeamFactory(
subscription__customer=UserFactory().customer,
subscription__plan_id=1,
subscription__is_legacy=True,
)
team.team_users.create(user=UserFactory()) team.team_users.create(user=UserFactory())
self.assertFalse(has_non_legacy_subscription(team.team_users.first().user)) self.assertFalse(has_non_legacy_subscription(team.team_users.first().user))
def test_false_when_team_subscription_active_and_is_legacy(self): def test_false_when_team_subscription_active_and_is_legacy(self):
team = TeamFactory( team = TeamFactory(
subscription__customer=UserFactory().customer,
subscription__plan_id=1, subscription__plan_id=1,
subscription__status=list(looper.models.Subscription._ACTIVE_STATUSES)[0], subscription__status=list(looper.models.Subscription._ACTIVE_STATUSES)[0],
subscription__is_legacy=True, subscription__is_legacy=True,

View File

@ -19,12 +19,14 @@ class TestAddToTeams(TestCase):
emails=['test1@example.com', 'test2@example.com'], emails=['test1@example.com', 'test2@example.com'],
name='Team Awesome', name='Team Awesome',
subscription__status='active', subscription__status='active',
subscription__customer=UserFactory().customer,
) )
cls.team_unlimited = TeamFactory( cls.team_unlimited = TeamFactory(
seats=None, seats=None,
name='Team Unlimited', name='Team Unlimited',
email_domain='my-awesome-blender-studio.org', email_domain='my-awesome-blender-studio.org',
subscription__status='active', subscription__status='active',
subscription__customer=UserFactory().customer,
) )
@responses.activate @responses.activate
@ -150,6 +152,7 @@ class TestAddToTeams(TestCase):
name='Team Unlimited', name='Team Unlimited',
email_domain='some-domain.com', email_domain='some-domain.com',
subscription__status='active', subscription__status='active',
subscription__customer=UserFactory().customer,
) )
self.assertTrue(has_active_subscription(user)) self.assertTrue(has_active_subscription(user))
@ -182,6 +185,7 @@ class TestAddToTeams(TestCase):
name='Team Unlimited', name='Team Unlimited',
email_domain='some-domain.com', email_domain='some-domain.com',
subscription__status='active', subscription__status='active',
subscription__customer=UserFactory().customer,
) )
self.assertEqual(team.email_domain, 'some-domain.com') self.assertEqual(team.email_domain, 'some-domain.com')
@ -232,6 +236,7 @@ class TestAddToTeams(TestCase):
name='Team Unlimited', name='Team Unlimited',
email_domain='edu.some-domain.com', email_domain='edu.some-domain.com',
subscription__status='active', subscription__status='active',
subscription__customer=UserFactory().customer,
) )
self.assertEqual(team.email_domain, 'edu.some-domain.com') self.assertEqual(team.email_domain, 'edu.some-domain.com')
@ -265,6 +270,7 @@ class TestAddToTeams(TestCase):
name='Team Unlimited', name='Team Unlimited',
email_domain='edu.some-domain.com', email_domain='edu.some-domain.com',
subscription__status='active', subscription__status='active',
subscription__customer=UserFactory().customer,
) )
self.assertEqual(team.email_domain, 'edu.some-domain.com') self.assertEqual(team.email_domain, 'edu.some-domain.com')

View File

@ -63,7 +63,7 @@ class TestGETJoinView(BaseSubscriptionTestCase):
) )
self.assertContains( self.assertContains(
response, response,
'<input type="email" name="email" value="jane.doe@example.com" placeholder="mail@example.com" class="form-control" required id="id_email">', '<input type="email" name="email" value="jane.doe@example.com" placeholder="mail@example.com" class="form-control" required id="id_email" maxlength="320">',
html=True, html=True,
) )

View File

@ -57,16 +57,16 @@ class TestReceiptPDFView(TestCase):
def setUpClass(cls): def setUpClass(cls):
super().setUpClass() super().setUpClass()
user = create_customer_with_billing_address(email='mail1@example.com') customer = create_customer_with_billing_address(email='mail1@example.com')
cls.payment_method = PaymentMethodFactory(user=user) cls.payment_method = PaymentMethodFactory(customer=customer)
cls.paid_order = OrderFactory( cls.paid_order = OrderFactory(
user=user, customer=customer,
price=990, price=990,
status='paid', status='paid',
tax_country='NL', tax_country='NL',
payment_method=cls.payment_method, payment_method=cls.payment_method,
subscription__customer=customer,
subscription__payment_method=cls.payment_method, subscription__payment_method=cls.payment_method,
subscription__user=user,
subscription__plan__product__name='Blender Studio Subscription', subscription__plan__product__name='Blender Studio Subscription',
) )
@ -87,15 +87,15 @@ class TestReceiptPDFView(TestCase):
def test_get_pdf_unpaid_order_not_found(self): def test_get_pdf_unpaid_order_not_found(self):
unpaid_order = OrderFactory( unpaid_order = OrderFactory(
user=self.payment_method.user, customer=self.payment_method.customer,
price=990, price=990,
tax_country='NL', tax_country='NL',
payment_method=self.payment_method, payment_method=self.payment_method,
subscription__customer=self.payment_method.customer,
subscription__payment_method=self.payment_method, subscription__payment_method=self.payment_method,
subscription__user=self.payment_method.user,
subscription__plan_id=1, subscription__plan_id=1,
) )
self.client.force_login(unpaid_order.user) self.client.force_login(unpaid_order.customer.user)
url = reverse('subscriptions:receipt-pdf', kwargs={'order_id': unpaid_order.pk}) url = reverse('subscriptions:receipt-pdf', kwargs={'order_id': unpaid_order.pk})
response = self.client.get(url) response = self.client.get(url)
@ -118,7 +118,7 @@ class TestReceiptPDFView(TestCase):
self.assertEqual(404, response.status_code) self.assertEqual(404, response.status_code)
def test_get_pdf_has_logo(self): def test_get_pdf_has_logo(self):
self.client.force_login(self.paid_order.user) self.client.force_login(self.paid_order.customer.user)
url = reverse('subscriptions:receipt-pdf', kwargs={'order_id': self.paid_order.pk}) url = reverse('subscriptions:receipt-pdf', kwargs={'order_id': self.paid_order.pk})
response = self.client.get(url) response = self.client.get(url)
@ -139,7 +139,9 @@ class TestReceiptPDFView(TestCase):
tax_type=looper.taxes.TaxType.VAT_CHARGE, tax_type=looper.taxes.TaxType.VAT_CHARGE,
tax_rate=Decimal(19), tax_rate=Decimal(19),
) )
user = UserFactory()
order = OrderFactory( order = OrderFactory(
customer=user.customer,
price=taxable.price, price=taxable.price,
status='paid', status='paid',
tax=taxable.tax, tax=taxable.tax,
@ -147,9 +149,10 @@ class TestReceiptPDFView(TestCase):
tax_type=taxable.tax_type.value, tax_type=taxable.tax_type.value,
tax_rate=taxable.tax_rate, tax_rate=taxable.tax_rate,
email='billing@example.com', email='billing@example.com',
subscription__customer=user.customer,
subscription__plan_id=1, subscription__plan_id=1,
) )
self.client.force_login(order.user) self.client.force_login(order.customer.user)
url = reverse('subscriptions:receipt-pdf', kwargs={'order_id': order.pk}) url = reverse('subscriptions:receipt-pdf', kwargs={'order_id': order.pk})
response = self.client.get(url) response = self.client.get(url)
@ -181,7 +184,9 @@ class TestReceiptPDFView(TestCase):
tax_type=looper.taxes.TaxType.VAT_REVERSE_CHARGE, tax_type=looper.taxes.TaxType.VAT_REVERSE_CHARGE,
tax_rate=Decimal(19), tax_rate=Decimal(19),
) )
user = UserFactory()
order = OrderFactory( order = OrderFactory(
customer=user.customer,
price=taxable.price, price=taxable.price,
status='paid', status='paid',
tax=taxable.tax, tax=taxable.tax,
@ -190,9 +195,10 @@ class TestReceiptPDFView(TestCase):
tax_rate=taxable.tax_rate, tax_rate=taxable.tax_rate,
vat_number='DE123456789', vat_number='DE123456789',
email='billing@example.com', email='billing@example.com',
subscription__customer=user.customer,
subscription__plan_id=1, subscription__plan_id=1,
) )
self.client.force_login(order.user) self.client.force_login(order.customer.user)
url = reverse('subscriptions:receipt-pdf', kwargs={'order_id': order.pk}) url = reverse('subscriptions:receipt-pdf', kwargs={'order_id': order.pk})
response = self.client.get(url) response = self.client.get(url)
@ -229,7 +235,9 @@ class TestReceiptPDFView(TestCase):
tax_type=looper.taxes.TaxType.VAT_CHARGE, tax_type=looper.taxes.TaxType.VAT_CHARGE,
tax_rate=Decimal(21), tax_rate=Decimal(21),
) )
user = UserFactory()
order = OrderFactory( order = OrderFactory(
customer=user.customer,
price=taxable.price, price=taxable.price,
status='paid', status='paid',
tax=taxable.tax, tax=taxable.tax,
@ -238,9 +246,10 @@ class TestReceiptPDFView(TestCase):
tax_rate=taxable.tax_rate, tax_rate=taxable.tax_rate,
vat_number='NL123456789', vat_number='NL123456789',
email='billing@example.com', email='billing@example.com',
subscription__customer=user.customer,
subscription__plan_id=1, subscription__plan_id=1,
) )
self.client.force_login(order.user) self.client.force_login(order.customer.user)
url = reverse('subscriptions:receipt-pdf', kwargs={'order_id': order.pk}) url = reverse('subscriptions:receipt-pdf', kwargs={'order_id': order.pk})
response = self.client.get(url) response = self.client.get(url)
@ -268,15 +277,18 @@ class TestReceiptPDFView(TestCase):
@freeze_time('2023-02-08T11:12:20+01:00') @freeze_time('2023-02-08T11:12:20+01:00')
def test_get_pdf_total_no_vat(self): def test_get_pdf_total_no_vat(self):
user = UserFactory()
order = OrderFactory( order = OrderFactory(
customer=user.customer,
price=1000, price=1000,
currency='USD', currency='USD',
status='paid', status='paid',
tax_country='US', tax_country='US',
email='billing@example.com', email='billing@example.com',
subscription__customer=user.customer,
subscription__plan_id=1, subscription__plan_id=1,
) )
self.client.force_login(order.user) self.client.force_login(order.customer.user)
url = reverse('subscriptions:receipt-pdf', kwargs={'order_id': order.pk}) url = reverse('subscriptions:receipt-pdf', kwargs={'order_id': order.pk})
response = self.client.get(url) response = self.client.get(url)
@ -307,9 +319,11 @@ class TestReceiptPDFView(TestCase):
seats=4, seats=4,
emails=['test1@example.com', 'test2@example.com'], emails=['test1@example.com', 'test2@example.com'],
name='Team Awesome', name='Team Awesome',
subscription__customer=UserFactory().customer,
subscription__plan_id=1, subscription__plan_id=1,
) )
order = OrderFactory( order = OrderFactory(
customer=team.subscription.customer,
price=20000, price=20000,
currency='USD', currency='USD',
status='paid', status='paid',
@ -317,7 +331,7 @@ class TestReceiptPDFView(TestCase):
email='billing@example.com', email='billing@example.com',
subscription=team.subscription, subscription=team.subscription,
) )
self.client.force_login(order.user) self.client.force_login(order.customer.user)
url = reverse('subscriptions:receipt-pdf', kwargs={'order_id': order.pk}) url = reverse('subscriptions:receipt-pdf', kwargs={'order_id': order.pk})
response = self.client.get(url) response = self.client.get(url)
@ -348,10 +362,12 @@ class TestReceiptPDFView(TestCase):
seats=4, seats=4,
emails=['test1@example.com', 'test2@example.com'], emails=['test1@example.com', 'test2@example.com'],
name='Team Awesome', name='Team Awesome',
subscription__customer=UserFactory().customer,
subscription__plan_id=1, subscription__plan_id=1,
invoice_reference='PO #9876', invoice_reference='PO #9876',
) )
order = OrderFactory( order = OrderFactory(
customer=team.subscription.customer,
price=20000, price=20000,
currency='USD', currency='USD',
status='paid', status='paid',
@ -359,7 +375,7 @@ class TestReceiptPDFView(TestCase):
email='billing@example.com', email='billing@example.com',
subscription=team.subscription, subscription=team.subscription,
) )
self.client.force_login(order.user) self.client.force_login(order.customer.user)
url = reverse('subscriptions:receipt-pdf', kwargs={'order_id': order.pk}) url = reverse('subscriptions:receipt-pdf', kwargs={'order_id': order.pk})
response = self.client.get(url) response = self.client.get(url)

View File

@ -49,8 +49,8 @@ class TestSelectPlanVariationView(BaseSubscriptionTestCase):
self._assert_default_variation_selected_no_tax_usd(response) self._assert_default_variation_selected_no_tax_usd(response)
def test_get_displays_plan_selection_to_logged_in_nl(self): def test_get_displays_plan_selection_to_logged_in_nl(self):
user = create_customer_with_billing_address(vat_number='', country='NL') customer = create_customer_with_billing_address(vat_number='', country='NL')
self.client.force_login(user) self.client.force_login(customer.user)
response = self.client.get(self.url, REMOTE_ADDR=EURO_IPV4) response = self.client.get(self.url, REMOTE_ADDR=EURO_IPV4)
@ -60,8 +60,8 @@ class TestSelectPlanVariationView(BaseSubscriptionTestCase):
self._assert_default_variation_selected_tax_21_eur(response) self._assert_default_variation_selected_tax_21_eur(response)
def test_get_displays_plan_selection_to_logged_in_de(self): def test_get_displays_plan_selection_to_logged_in_de(self):
user = create_customer_with_billing_address(vat_number='', country='DE') customer = create_customer_with_billing_address(vat_number='', country='DE')
self.client.force_login(user) self.client.force_login(customer.user)
response = self.client.get(self.url, REMOTE_ADDR=EURO_IPV4) response = self.client.get(self.url, REMOTE_ADDR=EURO_IPV4)
@ -71,10 +71,10 @@ class TestSelectPlanVariationView(BaseSubscriptionTestCase):
self._assert_default_variation_selected_tax_19_eur(response) self._assert_default_variation_selected_tax_19_eur(response)
def test_get_displays_plan_selection_to_logged_in_us(self): def test_get_displays_plan_selection_to_logged_in_us(self):
user = create_customer_with_billing_address( customer = create_customer_with_billing_address(
vat_number='', country='US', region='NY', postal_code='12001' vat_number='', country='US', region='NY', postal_code='12001'
) )
self.client.force_login(user) self.client.force_login(customer.user)
response = self.client.get(self.url) response = self.client.get(self.url)
@ -84,10 +84,10 @@ class TestSelectPlanVariationView(BaseSubscriptionTestCase):
self._assert_plan_selector_no_tax(response) self._assert_plan_selector_no_tax(response)
def test_get_team_displays_plan_selection_to_logged_in_us(self): def test_get_team_displays_plan_selection_to_logged_in_us(self):
user = create_customer_with_billing_address( customer = create_customer_with_billing_address(
vat_number='', country='US', region='NY', postal_code='12001' vat_number='', country='US', region='NY', postal_code='12001'
) )
self.client.force_login(user) self.client.force_login(customer.user)
response = self.client.get(self.url_team) response = self.client.get(self.url_team)

View File

@ -174,7 +174,7 @@ class User(AbstractUser):
self.delete_oauth() self.delete_oauth()
# If there are no orders, the user account can be deleted # If there are no orders, the user account can be deleted
if self.order_set.count() == 0: if self.customer.order_set.count() == 0:
logger.warning( logger.warning(
'User pk=%s requested deletion and has no orders: deleting the account', 'User pk=%s requested deletion and has no orders: deleting the account',
self.pk, self.pk,
@ -199,7 +199,7 @@ class User(AbstractUser):
logger.warning('Anonymized user pk=%s', self.pk) logger.warning('Anonymized user pk=%s', self.pk)
logger.warning('Soft-deleting payment methods records of user pk=%s', self.pk) logger.warning('Soft-deleting payment methods records of user pk=%s', self.pk)
for payment_method in self.paymentmethod_set.all(): for payment_method in self.customer.paymentmethod_set.all():
payment_method.recognisable_name = '<deleted>' payment_method.recognisable_name = '<deleted>'
logger.warning( logger.warning(
'Deleting payment method %s of user pk=%s at the payment gateway', 'Deleting payment method %s of user pk=%s at the payment gateway',
@ -208,17 +208,14 @@ class User(AbstractUser):
) )
payment_method.delete() payment_method.delete()
logger.warning('Deleting address records of user pk=%s', self.pk) customer_id = self.customer.pk
looper.models.Address.objects.filter(user_id=self.pk).delete() logger.warning('Deleting address records of customer pk=%s', customer_id)
looper.models.Address.objects.filter(customer_id=customer_id).delete()
logger.warning('Anonymizing Customer record of user pk=%s', self.pk) logger.warning('Deleting gateway customer ID records of customer pk=%s', customer_id)
looper.models.Customer.objects.exclude(user_id=None).filter(user_id=self.pk).update( looper.models.GatewayCustomerId.objects.filter(customer_id=customer_id).delete()
billing_email=f'{username}@example.com',
full_name='',
)
looper.models.GatewayCustomerId.objects.filter(user_id=self.pk).delete()
logger.warning('Deleting user pk=%s from teams', self.pk)
subscriptions.models.TeamUsers.objects.filter(user_id=self.pk).delete() subscriptions.models.TeamUsers.objects.filter(user_id=self.pk).delete()
logger.warning('Anonymizing comments of user pk=%s', self.pk) logger.warning('Anonymizing comments of user pk=%s', self.pk)

View File

@ -135,7 +135,7 @@ def handle_deletion_request(pk: int) -> bool:
try: try:
unsubscribe_from_newsletters(pk=pk) unsubscribe_from_newsletters(pk=pk)
except Exception: except Exception:
logger.warning('Error while trying to unsubscribe user pk=%s from newsletters') logger.warning('Error while trying to unsubscribe user pk=%s from newsletters', pk)
user.anonymize_or_delete() user.anonymize_or_delete()
return True return True

View File

@ -10,11 +10,12 @@ from looper.tests.factories import (
TransactionFactory, TransactionFactory,
create_customer_with_billing_address, create_customer_with_billing_address,
) )
import looper.models
from comments.queries import set_comment_like from comments.queries import set_comment_like
from common.tests.factories.comments import CommentFactory from common.tests.factories.comments import CommentFactory
from common.tests.factories.subscriptions import TeamFactory from common.tests.factories.subscriptions import TeamFactory
from common.tests.factories.users import UserFactory from common.tests.factories.users import UserFactory, OAuthUserInfoFactory, OAuthUserTokenFactory
import users.tasks as tasks import users.tasks as tasks
import users.tests.util as util import users.tests.util as util
@ -50,9 +51,13 @@ class TestTasks(TestCase):
def test_handle_deletion_request(self): def test_handle_deletion_request(self):
now = timezone.now() now = timezone.now()
user = create_customer_with_billing_address( customer = create_customer_with_billing_address(
email='mail1@example.com', date_deletion_requested=now - timedelta(days=30) email='mail1@example.com', date_deletion_requested=now - timedelta(days=30)
) )
user = customer.user
OAuthUserInfoFactory(user=user, oauth_user_id=223344)
OAuthUserTokenFactory(user=user)
OAuthUserTokenFactory(user=user)
# this user made some comments # this user made some comments
user_comments = [CommentFactory(user=user) for _ in range(2)] user_comments = [CommentFactory(user=user) for _ in range(2)]
# this user liked some comments as well # this user liked some comments as well
@ -103,22 +108,27 @@ class TestTasks(TestCase):
def test_handle_deletion_request_user_has_orders(self): def test_handle_deletion_request_user_has_orders(self):
now = timezone.now() now = timezone.now()
user = create_customer_with_billing_address( customer = create_customer_with_billing_address(
email='mail1@example.com', date_deletion_requested=now - timedelta(days=30) email='mail1@example.com', date_deletion_requested=now - timedelta(days=30)
) )
user = customer.user
OAuthUserInfoFactory(user=user, oauth_user_id=223344)
OAuthUserTokenFactory(user=user)
OAuthUserTokenFactory(user=user)
# this user has a subscription with an order and a transaction # this user has a subscription with an order and a transaction
payment_method = PaymentMethodFactory(user=user) payment_method = PaymentMethodFactory(customer=customer, token='fake-token')
transaction = TransactionFactory( transaction = TransactionFactory(
user=user, customer=customer,
order__price=990, order__customer=customer,
order__tax_country='NL',
order__payment_method=payment_method, order__payment_method=payment_method,
order__price=990,
order__subscription__customer=customer,
order__subscription__payment_method=payment_method, order__subscription__payment_method=payment_method,
order__subscription__user=user,
order__subscription__status='cancelled', order__subscription__status='cancelled',
order__user=user, order__tax_country='NL',
payment_method=payment_method, payment_method=payment_method,
) )
billing_address = customer.billing_address
# this user made some comments # this user made some comments
user_comments = [CommentFactory(user=user) for _ in range(2)] user_comments = [CommentFactory(user=user) for _ in range(2)]
# this user liked some comments as well # this user liked some comments as well
@ -143,8 +153,9 @@ class TestTasks(TestCase):
f'Anonymized user pk={user.pk}', f'Anonymized user pk={user.pk}',
f'Soft-deleting payment methods records of user pk={user.pk}', f'Soft-deleting payment methods records of user pk={user.pk}',
rf'Deleting payment method \d+ of user pk={user.pk} at the payment gateway', rf'Deleting payment method \d+ of user pk={user.pk} at the payment gateway',
f'Deleting address records of user pk={user.pk}', f'Deleting address records of customer pk={customer.pk}',
f'Anonymizing Customer record of user pk={user.pk}', f'Deleting gateway customer ID records of customer pk={customer.pk}',
f'Deleting user pk={user.pk} from teams',
f'Anonymizing comments of user pk={user.pk}', f'Anonymizing comments of user pk={user.pk}',
f'Anonymizing likes of user pk={user.pk}', f'Anonymizing likes of user pk={user.pk}',
f'Deleting actions of user pk={user.pk}', f'Deleting actions of user pk={user.pk}',
@ -166,14 +177,11 @@ class TestTasks(TestCase):
self.assertEqual(user.full_name, '') self.assertEqual(user.full_name, '')
self.assertTrue(user.email.startswith('del')) self.assertTrue(user.email.startswith('del'))
self.assertTrue(user.email.endswith('@example.com')) self.assertTrue(user.email.endswith('@example.com'))
user.customer.refresh_from_db() # billing address was deleted
self.assertTrue(user.customer.billing_email.startswith('del'), user.customer.billing_email) with self.assertRaises(looper.models.Address.DoesNotExist):
self.assertTrue( billing_address.refresh_from_db()
user.customer.billing_email.endswith('@example.com'), user.customer.billing_email customer.refresh_from_db()
) self.assertEqual(customer.paymentmethod_set.first().recognisable_name, '')
self.assertEqual(user.customer.full_name, '', user.customer.full_name)
self.assertEqual(user.address_set.count(), 0)
self.assertEqual(user.paymentmethod_set.first().recognisable_name, '')
# user actions got deleted # user actions got deleted
for action in user_actions: for action in user_actions:
@ -195,22 +203,23 @@ class TestTasks(TestCase):
def test_handle_deletion_request_user_has_not_yet_cancelled_subscription(self): def test_handle_deletion_request_user_has_not_yet_cancelled_subscription(self):
now = timezone.now() now = timezone.now()
user = create_customer_with_billing_address( customer = create_customer_with_billing_address(
full_name='Joe Dane', full_name='Joe Dane',
email='mail1@example.com', email='mail1@example.com',
date_deletion_requested=now - timedelta(days=30), date_deletion_requested=now - timedelta(days=30),
) )
user = customer.user
# this user has a subscription with an order and a transaction # this user has a subscription with an order and a transaction
payment_method = PaymentMethodFactory(user=user) payment_method = PaymentMethodFactory(customer=customer)
transaction = TransactionFactory( transaction = TransactionFactory(
user=user, customer=customer,
order__price=990, order__customer=customer,
order__tax_country='NL',
order__payment_method=payment_method, order__payment_method=payment_method,
order__price=990,
order__subscription__customer=customer,
order__subscription__payment_method=payment_method, order__subscription__payment_method=payment_method,
order__subscription__user=user,
order__subscription__status='on-hold', order__subscription__status='on-hold',
order__user=user, order__tax_country='NL',
payment_method=payment_method, payment_method=payment_method,
) )
@ -238,7 +247,7 @@ class TestTasks(TestCase):
def test_handle_deletion_request_user_has_orders_and_is_on_a_team(self): def test_handle_deletion_request_user_has_orders_and_is_on_a_team(self):
now = timezone.now() now = timezone.now()
team = TeamFactory( team = TeamFactory(
subscription__user=create_customer_with_billing_address( subscription__customer=create_customer_with_billing_address(
full_name='Joe Manager Dane', full_name='Joe Manager Dane',
email='mail1@example.com', email='mail1@example.com',
) )
@ -249,25 +258,27 @@ class TestTasks(TestCase):
team.users.add(user_to_be_deleted) team.users.add(user_to_be_deleted)
self.assertEqual(3, team.users.count()) self.assertEqual(3, team.users.count())
# this user also has a subscription with an order and a transaction # this user also has a subscription with an order and a transaction
payment_method = PaymentMethodFactory(user=user_to_be_deleted) payment_method = PaymentMethodFactory(
customer=user_to_be_deleted.customer, token='fake-token'
)
TransactionFactory( TransactionFactory(
user=user_to_be_deleted, customer=user_to_be_deleted.customer,
order__price=990, order__price=990,
order__tax_country='NL', order__tax_country='NL',
order__customer=user_to_be_deleted.customer,
order__payment_method=payment_method, order__payment_method=payment_method,
order__subscription__payment_method=payment_method, order__subscription__payment_method=payment_method,
order__subscription__user=user_to_be_deleted, order__subscription__customer=user_to_be_deleted.customer,
order__subscription__status='cancelled', order__subscription__status='cancelled',
order__user=user_to_be_deleted,
payment_method=payment_method, payment_method=payment_method,
) )
tasks.handle_deletion_request.task_function(pk=user_to_be_deleted.pk) tasks.handle_deletion_request.task_function(pk=user_to_be_deleted.pk)
# sanity check: nothing happened to the user owning the team subscription # sanity check: nothing happened to the user owning the team subscription
team.subscription.user.refresh_from_db() team.subscription.customer.user.refresh_from_db()
self.assertEqual('Joe Manager Dane', team.subscription.user.full_name) self.assertEqual('Joe Manager Dane', team.subscription.customer.user.full_name)
self.assertTrue(team.subscription.user.is_active) self.assertTrue(team.subscription.customer.user.is_active)
# user wasn't deleted but anonymised # user wasn't deleted but anonymised
user_to_be_deleted.refresh_from_db() user_to_be_deleted.refresh_from_db()
@ -283,7 +294,7 @@ class TestTasks(TestCase):
def test_handle_deletion_request_user_and_is_on_a_team(self): def test_handle_deletion_request_user_and_is_on_a_team(self):
now = timezone.now() now = timezone.now()
team = TeamFactory( team = TeamFactory(
subscription__user=create_customer_with_billing_address( subscription__customer=create_customer_with_billing_address(
full_name='Joe Manager Dane', full_name='Joe Manager Dane',
email='mail1@example.com', email='mail1@example.com',
) )
@ -297,9 +308,9 @@ class TestTasks(TestCase):
tasks.handle_deletion_request.task_function(pk=user_to_be_deleted.pk) tasks.handle_deletion_request.task_function(pk=user_to_be_deleted.pk)
# sanity check: nothing happened to the user owning the team subscription # sanity check: nothing happened to the user owning the team subscription
team.subscription.user.refresh_from_db() team.subscription.customer.user.refresh_from_db()
self.assertEqual('Joe Manager Dane', team.subscription.user.full_name) self.assertEqual('Joe Manager Dane', team.subscription.customer.user.full_name)
self.assertTrue(team.subscription.user.is_active) self.assertTrue(team.subscription.customer.user.is_active)
# user was deleted # user was deleted
with self.assertRaises(User.DoesNotExist): with self.assertRaises(User.DoesNotExist):

View File

@ -145,7 +145,9 @@ def mock_mailgun_responses() -> None:
def create_admin_log_user() -> User: def create_admin_log_user() -> User:
"""Create the admin user used for logging.""" """Create the admin user used for logging."""
admin_user = UserFactory(id=1, email='admin@blender.studio', is_staff=True, is_superuser=True) admin_user, _ = User.objects.get_or_create(
id=1, email='admin@blender.studio', is_staff=True, is_superuser=True
)
# Reset ID sequence to avoid clashing with an already used ID 1 # Reset ID sequence to avoid clashing with an already used ID 1
UserFactory.reset_sequence(100, force=True) UserFactory.reset_sequence(100, force=True)
return admin_user return admin_user