Handle failed payments subscriptions in paddle (#1327)

* Handle failed payments subscriptions in paddle

* Added tests

* Remove unused import

* Remove unused import

Co-authored-by: Adrià Casajús <adria.casajus@proton.ch>
This commit is contained in:
Adrià Casajús 2022-09-30 17:51:06 +02:00 committed by GitHub
parent d415974e3b
commit faaff7e9b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 71 additions and 1 deletions

32
app/paddle_callback.py Normal file
View file

@ -0,0 +1,32 @@
import arrow
from app.db import Session
from app.email_utils import send_email, render
from app.log import LOG
from app.models import Subscription
from app import paddle_utils
def failed_payment(sub: Subscription, subscription_id: str):
LOG.w(
"Subscription failed payment %s for %s (sub %s)",
subscription_id,
sub.user,
sub.id,
)
sub.cancelled = True
Session.commit()
user = sub.user
paddle_utils.cancel_subscription(subscription_id)
send_email(
user.email,
"SimpleLogin - your subscription has failed to be renewed",
render(
"transactional/subscription-cancel.txt",
end_date=arrow.arrow.datetime.utcnow(),
),
)

View file

@ -29,7 +29,7 @@ from sentry_sdk.integrations.flask import FlaskIntegration
from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration
from werkzeug.middleware.proxy_fix import ProxyFix
from app import paddle_utils, config
from app import paddle_utils, config, paddle_callback
from app.admin_model import (
SLAdminIndexView,
UserAdmin,
@ -543,6 +543,11 @@ def setup_paddle_callback(app: Flask):
sub: Subscription = Subscription.get_by(subscription_id=subscription_id)
if sub:
next_bill_date = request.form.get("next_bill_date")
if not next_bill_date:
paddle_callback.failed_payment(sub, subscription_id)
return "OK"
LOG.d(
"Update subscription %s %s on %s, next bill date %s",
subscription_id,

View file

@ -0,0 +1,33 @@
import arrow
from app import paddle_callback
from app.db import Session
from app.mail_sender import mail_sender
from app.models import Subscription, PlanEnum
from tests.utils import create_new_user, random_token
@mail_sender.store_emails_test_decorator
def test_failed_payments():
user = create_new_user()
paddle_sub_id = random_token()
sub = Subscription.create(
user_id=user.id,
cancel_url="https://checkout.paddle.com/subscription/cancel?user=1234",
update_url="https://checkout.paddle.com/subscription/update?user=1234",
subscription_id=paddle_sub_id,
event_time=arrow.now(),
next_bill_date=arrow.now().shift(days=10).date(),
plan=PlanEnum.monthly,
commit=True,
)
Session.commit()
paddle_callback.failed_payment(sub, paddle_sub_id)
sub = Subscription.get_by(subscription_id=paddle_sub_id)
assert sub.cancelled
assert 1 == len(mail_sender.get_stored_emails())
mail_sent = mail_sender.get_stored_emails()[0]
assert mail_sent.envelope_to == user.email