Skip to content

Commit

Permalink
Merge pull request #1176 from texastribune/slack-updates
Browse files Browse the repository at this point in the history
Slack updates (cancellations)
  • Loading branch information
ashley-hebler committed Apr 4, 2024
2 parents 175956f + 75eec1d commit ccfda81
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 13 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ Environment
| `SLACK_API_KEY` | |
| `SLACK_CHANNEL` | #donations |
| `SLACK_CHANNEL_CANCELLATIONS` | #bot-cancellations |
| `SLACK_CIRCLE_NOTIFICATIONS`| #circle-failures |
| `DEFAULT_MAIL_SENDER` | foo@bar.org |
| `MAIL_SERVER` | mail.server.com |
| `MAIL_USERNAME` | |
Expand Down
3 changes: 3 additions & 0 deletions app.json
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,9 @@
"SLACK_CHANNEL_CANCELLATIONS": {
"required": true
},
"SLACK_CIRCLE_NOTIFICATIONS": {
"required": true
},
"STRIPE_PRODUCT_SUSTAINING": {
"required": true
},
Expand Down
20 changes: 8 additions & 12 deletions server/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
REPORT_URI,
SENTRY_DSN,
SENTRY_ENVIRONMENT,
SLACK_CHANNEL_CANCELLATIONS,
STRIPE_PRODUCTS,
STRIPE_WEBHOOK_SECRET,
TIMEZONE,
Expand All @@ -59,6 +58,7 @@
send_email_new_business_membership,
send_multiple_account_warning,
send_slack_message,
send_cancellation_notification,
name_splitter,
)

Expand Down Expand Up @@ -971,6 +971,7 @@ def payment_intent_succeeded(event):
@celery.task(name="app.customer_subscription_deleted")
def customer_subscription_deleted(event):
subscription = stripe.Subscription.retrieve(event["data"]["object"]["id"], expand=["customer", "latest_invoice.charge"])
donation_type = subscription.get("donation_type", subscription["plan"]["metadata"].get("type", "membership"))
customer = subscription["customer"]
charge = subscription["latest_invoice"]["charge"]
method = subscription["cancellation_details"].get('comment') or 'Staff'
Expand All @@ -983,17 +984,12 @@ def customer_subscription_deleted(event):
if rdo is None:
return

text = f"{contact.name}'s ${rdo.amount}/{rdo.installment_period} donation was cancelled due to {reason}"
if reason == "cancellation_requested":
text += f" ({method})"

message = {
"text": text,
"channel": SLACK_CHANNEL_CANCELLATIONS,
"icon_emoji": ":no_good:"
}
# notifications for ended donations
try:
send_cancellation_notification(contact, rdo, donation_type, reason, method)
except Exception as e:
app.logger.error(f"Failed to send cancellation notification: {e}")

send_slack_message(message, username="Cancellation bot")


@celery.task(name="app.subscription_schedule_updated")
Expand All @@ -1005,7 +1001,7 @@ def subscription_schedule_updated(event):
rdo = RDO.get(subscription_id=sub_schedule["id"])
except Exception:
return # if no RDO is found with the given subscription schedule id, then there is nothing to update

subscription_id = sub_schedule["subscription"]

if subscription_id:
Expand Down
1 change: 1 addition & 0 deletions server/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ def bool_env(val):
ENABLE_SLACK = bool_env("ENABLE_SLACK")
SLACK_CHANNEL = os.getenv("SLACK_CHANNEL", "#stripe")
SLACK_CHANNEL_CANCELLATIONS = os.getenv("SLACK_CHANNEL_CANCELLATIONS", "#tech-test")
SLACK_CIRCLE_NOTIFICATIONS = os.getenv("SLACK_CIRCLE_NOTIFICATIONS", "#tech-test")
SLACK_API_KEY = os.getenv("SLACK_API_KEY")

########
Expand Down
54 changes: 53 additions & 1 deletion server/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
MULTIPLE_ACCOUNT_WARNING_MAIL_RECIPIENT,
SLACK_API_KEY,
SLACK_CHANNEL,
SLACK_CHANNEL_CANCELLATIONS,
SLACK_CIRCLE_NOTIFICATIONS,
STRIPE_PRODUCTS,
TIMEZONE,
)
Expand Down Expand Up @@ -134,6 +136,56 @@ def construct_slack_attachment(

return attachment

def get_circle_amount(rdo):
"""
Get the amount for a circle donation based on the three year total.
"""
amount = rdo.amount
period = rdo.installment_period
amount = quantize(amount) / 3
if period == "monthly":
amount = amount / 12
return amount

def send_cancellation_notification(contact, rdo, donation_type, reason, method):
"""
Send a notification about a donation cancellation to Slack.
Rules:
- If the donation is a circle membership, notifications go to circle channel
- Only circle gets notfications for anything other than "cancellation_requested"
- For non-circle, if the reason is "cancellation_requested" we send to the general cancellations channel
"""

name = contact.name if contact.name else "An unknown user"
amount = rdo.amount
period = rdo.installment_period

if reason != "cancellation_requested" and donation_type != 'circle':
logging.info(f"Skipping cancellation notification for {name}. Reason: {reason} Donation type: {donation_type} Method: {method} Amount: {amount}")
return

channel = SLACK_CHANNEL_CANCELLATIONS

if donation_type == 'circle':
channel = SLACK_CIRCLE_NOTIFICATIONS
try:
amount = get_circle_amount(rdo)
except Exception as e:
logging.error(f"Error getting circle amount: {e}")
text = f"{name}'s ${amount}/{period} Circle donation was cancelled due to {reason}"
else:
text = f"{name}'s ${amount}/{period} {donation_type} subscription was cancelled"

if reason == "cancellation_requested":
text += f" ({method})"

message = {
"text": text,
"channel": channel,
"icon_emoji": ":no_good:"
}
send_slack_message(message, username="Cancellation bot")


def send_multiple_account_warning(contact):
"""
Expand Down Expand Up @@ -290,7 +342,7 @@ def donation_adder(customer: str, amount: int, pay_fees: bool, interval: str, ye
# We use stripe's subscription trial functionality here so that we can control when the next charge for the donor
# will take place (trial_end). This means we can create the subscription now, even though the next expected charge
# date won't be for another 13 days. Handy for moving existing recurring donations to stripe subscriptions or for
# setting a donor up with a different recurring donation amount but keeping to the same date.
# setting a donor up with a different recurring donation amount but keeping to the same date.
subscription = stripe.Subscription.create(
customer = customer["id"],
default_source = source["id"],
Expand Down

0 comments on commit ccfda81

Please sign in to comment.