|
3 | 3 |
|
4 | 4 | https://docs.dj-stripe.dev/en/master/usage/webhooks/.
|
5 | 5 | """
|
| 6 | +import requests |
6 | 7 | import structlog
|
7 | 8 | from django.conf import settings
|
| 9 | +from django.contrib import humanize |
| 10 | +from django.db.models import Sum |
8 | 11 | from django.utils import timezone
|
9 | 12 | from djstripe import models as djstripe
|
10 | 13 | from djstripe import webhooks
|
11 |
| -from djstripe.enums import SubscriptionStatus |
| 14 | +from djstripe.enums import ChargeStatus, SubscriptionStatus |
12 | 15 |
|
13 | 16 | from readthedocs.organizations.models import Organization
|
14 | 17 | from readthedocs.payments.utils import cancel_subscription as cancel_stripe_subscription
|
| 18 | +from readthedocs.projects.models import Domain |
| 19 | +from readthedocs.sso.models import SSOIntegration |
15 | 20 | from readthedocs.subscriptions.notifications import (
|
16 | 21 | SubscriptionEndedNotification,
|
17 | 22 | SubscriptionRequiredNotification,
|
@@ -191,6 +196,88 @@ def subscription_canceled(event):
|
191 | 196 | notification.send()
|
192 | 197 | log.info("Notification sent.", recipient=owner)
|
193 | 198 |
|
| 199 | + total_spent = ( |
| 200 | + stripe_subscription.customer.charges.filter(status=ChargeStatus.succeeded) |
| 201 | + .aggregate(total=Sum("amount")) |
| 202 | + .get("total") |
| 203 | + or 0 |
| 204 | + ) |
| 205 | + if settings.SLACK_WEBHOOK_SALES_CHANNEL and total_spent > 0: |
| 206 | + start_date = stripe_subscription.start_date.strftime("%b %-d, %Y") |
| 207 | + timesince = humanize.naturaltime(stripe_subscription.start_date).split(",")[0] |
| 208 | + domains = Domain.objects.filter( |
| 209 | + project__organizations__in=[organization] |
| 210 | + ).count() |
| 211 | + try: |
| 212 | + sso_integration = organization.ssointegration.provider |
| 213 | + except SSOIntegration.DoesNotExist: |
| 214 | + sso_integration = "Read the Docs Auth" |
| 215 | + |
| 216 | + slack_message = { |
| 217 | + "blocks": [ |
| 218 | + { |
| 219 | + "type": "section", |
| 220 | + "text": {"type": "mrkdwn", "text": ":x: *Subscription canceled*"}, |
| 221 | + }, |
| 222 | + {"type": "divider"}, |
| 223 | + { |
| 224 | + "type": "section", |
| 225 | + "fields": [ |
| 226 | + { |
| 227 | + "type": "mrkdwn", |
| 228 | + "text": f":office: *Name:* {organization.name}", |
| 229 | + }, |
| 230 | + { |
| 231 | + "type": "mrkdwn", |
| 232 | + "text": f":dollar: *Plan:* {stripe_subscription.plan.id}", |
| 233 | + }, |
| 234 | + { |
| 235 | + "type": "mrkdwn", |
| 236 | + "text": f":hash: *Slug:* {organization.slug}", |
| 237 | + }, |
| 238 | + { |
| 239 | + "type": "mrkdwn", |
| 240 | + "text": f":person_frowning: *Stripe customer:* <https://dashboard.stripe.com/customers/{stripe_subscription.customer_id}|{stripe_subscription.customer_id}>", |
| 241 | + }, |
| 242 | + { |
| 243 | + "type": "mrkdwn", |
| 244 | + "text": f":date: *Customer since:* {start_date} (~{timesince})", |
| 245 | + }, |
| 246 | + { |
| 247 | + "type": "mrkdwn", |
| 248 | + "text": f":books: *Projects:* {organization.projects.count()}", |
| 249 | + }, |
| 250 | + {"type": "mrkdwn", "text": f":link: *Domains:* {domains}"}, |
| 251 | + { |
| 252 | + "type": "mrkdwn", |
| 253 | + "text": f":closed_lock_with_key: *Authentication:* {sso_integration}", |
| 254 | + }, |
| 255 | + { |
| 256 | + "type": "mrkdwn", |
| 257 | + "text": f":busts_in_silhouette: *Teams:* {organization.teams.count()}", |
| 258 | + }, |
| 259 | + ], |
| 260 | + }, |
| 261 | + { |
| 262 | + "type": "context", |
| 263 | + "elements": [ |
| 264 | + { |
| 265 | + "type": "mrkdwn", |
| 266 | + "text": "We should contact this customer and see if we can get some feedback from them.", |
| 267 | + } |
| 268 | + ], |
| 269 | + }, |
| 270 | + ] |
| 271 | + } |
| 272 | + try: |
| 273 | + requests.post( |
| 274 | + settings.SLACK_WEBHOOK_SALES_CHANNEL, |
| 275 | + data=slack_message, |
| 276 | + timeout=3, |
| 277 | + ) |
| 278 | + except requests.Timeout: |
| 279 | + log.warning("Timeout sending a message to Slack webhook") |
| 280 | + |
194 | 281 |
|
195 | 282 | @handler("customer.updated")
|
196 | 283 | def customer_updated_event(event):
|
|
0 commit comments