Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix stripe subscription upgrade failures #831

Merged
merged 2 commits into from
Sep 23, 2024
Merged

Fix stripe subscription upgrade failures #831

merged 2 commits into from
Sep 23, 2024

Conversation

nora-codecov
Copy link
Contributor

@nora-codecov nora-codecov commented Sep 19, 2024

Purpose/Motivation

We were eagerly updating the user's plan in the specific case where they already have a subscription and they are upgrading. We were updating without checking that the payment was successful, so in the case where we have updated the plan but the stripe payment fails, we were bumping the user all the way back to free tier.

Links to relevant tickets

codecov/engineering-team#2407
stripe's docs: https://docs.stripe.com/billing/subscriptions/pending-updates

What does this PR do?

Only update the plan if the payment was successful. If it's not successful, reject the changes and give they user the delinquent pop-up. The user in our db and in Stripe's system stays on the original plan until they payment is successful.

@nora-codecov nora-codecov requested review from ajay-sentry and a team September 19, 2024 23:11
@codecov-notifications
Copy link

codecov-notifications bot commented Sep 19, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

Copy link

codecov bot commented Sep 19, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 96.23%. Comparing base (6d7be25) to head (536f112).
Report is 1 commits behind head on main.

✅ All tests successful. No failed tests found.

Additional details and impacted files
@@             Coverage Diff             @@
##               main       #831   +/-   ##
===========================================
  Coverage   96.23000   96.23000           
===========================================
  Files           812        812           
  Lines         18575      18587   +12     
===========================================
+ Hits          17876      17888   +12     
  Misses          699        699           
Flag Coverage Δ
unit 92.47% <100.00%> (+<0.01%) ⬆️
unit-latest-uploader 92.47% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

# Only update if there isn't a scheduled subscription
if not subscription_schedule_id:
if not subscription.schedule:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

love this ngl

extra=dict(pending_update=indication_of_payment_failure),
)
else:
# payment successful
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will delinquent ever be true at this point where we'd want to set to false?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

love this suggestion, but "yes and"ed it with this change https://github.com/codecov/codecov-api/pull/831/files#diff-dda355f2f33801fe525e8ba51493017a8957e35710e9dc1d4affed3940e18685R56 (clearing delinquency in update_plan!)
From what I could tell, we are only using plan_service.update_plan in a situation where the owner should not be delinquent, so just make sure that field is set correctly while we're updating the owner obj.

Copy link
Contributor

@ajay-sentry ajay-sentry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good! Could we add the stripe docs you were looking at to the review description?

@codecov-qa
Copy link

codecov-qa bot commented Sep 23, 2024

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
2297 1 2296 6
View the top 1 failed tests by shortest run time
billing.tests.test_views.StripeWebhookHandlerTests test_customer_subscription_deleted_deactivates_all_repos
Stack Traces | 0.025s run time
self = &lt;billing.tests.test_views.StripeWebhookHandlerTests testMethod=test_customer_subscription_deleted_deactivates_all_repos&gt;

    def test_customer_subscription_deleted_deactivates_all_repos(self):
        RepositoryFactory(author=self.owner, activated=True, active=True)
        RepositoryFactory(author=self.owner, activated=True, active=True)
        RepositoryFactory(author=self.owner, activated=True, active=True)
    
&gt;       assert (
            self.owner.repository_set.filter(activated=True, active=True).count() == 3
        )
E       assert 2 == 3
E        +  where 2 = &lt;bound method QuerySet.count of &lt;RepositoryQuerySet [&lt;Repository: Repo&lt;Owner&lt;github/wesley45&gt;/lawyer&gt;&gt;, &lt;Repository: Repo&lt;Owner&lt;github/wesley45&gt;/use&gt;&gt;]&gt;&gt;()
E        +    where &lt;bound method QuerySet.count of &lt;RepositoryQuerySet [&lt;Repository: Repo&lt;Owner&lt;github/wesley45&gt;/lawyer&gt;&gt;, &lt;Repository: Repo&lt;Owner&lt;github/wesley45&gt;/use&gt;&gt;]&gt;&gt; = &lt;RepositoryQuerySet [&lt;Repository: Repo&lt;Owner&lt;github/wesley45&gt;/lawyer&gt;&gt;, &lt;Repository: Repo&lt;Owner&lt;github/wesley45&gt;/use&gt;&gt;]&gt;.count
E        +      where &lt;RepositoryQuerySet [&lt;Repository: Repo&lt;Owner&lt;github/wesley45&gt;/lawyer&gt;&gt;, &lt;Repository: Repo&lt;Owner&lt;github/wesley45&gt;/use&gt;&gt;]&gt; = &lt;bound method QuerySet.filter of &lt;django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager.&lt;locals&gt;.RelatedManager object at 0x7f3aaa3dc590&gt;&gt;(activated=True, active=True)
E        +        where &lt;bound method QuerySet.filter of &lt;django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager.&lt;locals&gt;.RelatedManager object at 0x7f3aaa3dc590&gt;&gt; = &lt;django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager.&lt;locals&gt;.RelatedManager object at 0x7f3aaa3dc590&gt;.filter
E        +          where &lt;django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager.&lt;locals&gt;.RelatedManager object at 0x7f3aaa3dc590&gt; = &lt;Owner: Owner&lt;github/wesley45&gt;&gt;.repository_set
E        +            where &lt;Owner: Owner&lt;github/wesley45&gt;&gt; = &lt;billing.tests.test_views.StripeWebhookHandlerTests testMethod=test_customer_subscription_deleted_deactivates_all_repos&gt;.owner

billing/tests/test_views.py:151: AssertionError

To view individual test run time comparison to the main branch, go to the Test Analytics Dashboard

Copy link

Test Failures Detected: Due to failing tests, we cannot provide coverage reports at this time.

❌ Failed Test Results:

Completed 2303 tests with 1 failed, 2296 passed and 6 skipped.

View the full list of failed tests

pytest

  • Class name: billing.tests.test_views.StripeWebhookHandlerTests
    Test name: test_customer_subscription_deleted_deactivates_all_repos

    self = <billing.tests.test_views.StripeWebhookHandlerTests testMethod=test_customer_subscription_deleted_deactivates_all_repos>

    def test_customer_subscription_deleted_deactivates_all_repos(self):
    RepositoryFactory(author=self.owner, activated=True, active=True)
    RepositoryFactory(author=self.owner, activated=True, active=True)
    RepositoryFactory(author=self.owner, activated=True, active=True)

    > assert (
    self.owner.repository_set.filter(activated=True, active=True).count() == 3
    )
    E assert 2 == 3
    E + where 2 = <bound method QuerySet.count of <RepositoryQuerySet [<Repository: Repo<Owner<github/wesley45>/lawyer>>, <Repository: Repo<Owner<github/wesley45>/use>>]>>()
    E + where <bound method QuerySet.count of <RepositoryQuerySet [<Repository: Repo<Owner<github/wesley45>/lawyer>>, <Repository: Repo<Owner<github/wesley45>/use>>]>> = <RepositoryQuerySet [<Repository: Repo<Owner<github/wesley45>/lawyer>>, <Repository: Repo<Owner<github/wesley45>/use>>]>.count
    E + where <RepositoryQuerySet [<Repository: Repo<Owner<github/wesley45>/lawyer>>, <Repository: Repo<Owner<github/wesley45>/use>>]> = <bound method QuerySet.filter of <django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager.<locals>.RelatedManager object at 0x7f3aaa3dc590>>(activated=True, active=True)
    E + where <bound method QuerySet.filter of <django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager.<locals>.RelatedManager object at 0x7f3aaa3dc590>> = <django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager.<locals>.RelatedManager object at 0x7f3aaa3dc590>.filter
    E + where <django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager.<locals>.RelatedManager object at 0x7f3aaa3dc590> = <Owner: Owner<github/wesley45>>.repository_set
    E + where <Owner: Owner<github/wesley45>> = <billing.tests.test_views.StripeWebhookHandlerTests testMethod=test_customer_subscription_deleted_deactivates_all_repos>.owner

    billing/tests/test_views.py:151: AssertionError

@nora-codecov nora-codecov added this pull request to the merge queue Sep 23, 2024
Merged via the queue into main with commit b70830f Sep 23, 2024
19 of 20 checks passed
@nora-codecov nora-codecov deleted the nora/2407 branch September 23, 2024 22:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants