Skip to content

Commit

Permalink
prints stats when running renewals cron script
Browse files Browse the repository at this point in the history
  • Loading branch information
smirolo committed Oct 7, 2024
1 parent a50c4df commit 543dcca
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 10 deletions.
10 changes: 7 additions & 3 deletions saas/management/commands/renewals.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,14 @@ def handle(self, *args, **options):
except Exception as err:
LOGGER.exception("recognize_income: %s", err)
try:
extend_subscriptions(end_period, dry_run=dry_run)
nb_renewals = extend_subscriptions(end_period, dry_run=dry_run)
self.stdout.write(" %d subscriptions renewed" % nb_renewals)
except Exception as err:
LOGGER.exception("extend_subscriptions: %s", err)
try:
create_charges_for_balance(
nb_charges = create_charges_for_balance(
end_period, dry_run=dry_run or no_charges)
self.stdout.write(" %d charges initiated" % nb_charges)
except Exception as err:
LOGGER.exception(
"Unable to create charges for balance on broker '%s'",
Expand All @@ -108,5 +110,7 @@ def handle(self, *args, **options):
# Trigger 'expires soon' notifications
expiration_periods = settings.EXPIRE_NOTICE_DAYS
for period in expiration_periods:
trigger_expiration_notices(
nb_notices = trigger_expiration_notices(
end_period, nb_days=period, dry_run=dry_run)
self.stdout.write(" %d %d-days expiration notices sent" % (
nb_notices, period))
34 changes: 27 additions & 7 deletions saas/renewals.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2022, DjaoDjin inc.
# Copyright (c) 2024, DjaoDjin inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -36,6 +36,7 @@
from . import humanize, settings, signals
from .backends import CardError, ProcessorError
from .compat import gettext_lazy as _, six
from .humanize import describe_period_name
from .models import (Charge, Plan, Price, Subscription, Transaction,
sum_dest_amount, get_period_usage, get_sub_event_id)
from .utils import datetime_or_now, get_organization_model
Expand Down Expand Up @@ -217,10 +218,12 @@ def extend_subscriptions(at_time=None, dry_run=False):
"""
Extend active subscriptions
"""
nb_renewals = 0
at_time = datetime_or_now(at_time)
LOGGER.info("extend subscriptions at %s ...", at_time)
for subscription in Subscription.objects.valid_for(
auto_renew=True, created_at__lte=at_time, ends_at__gt=at_time):
for subscription in Subscription.objects.valid_for(auto_renew=True,
created_at__lte=at_time, ends_at__gt=at_time).select_related(
'organization', 'plan'):
lower, upper = subscription.clipped_period_for(at_time)
# `relativedelta` will compute number of years, months, days, etc.
# `days` represents the difference in days after years and months have
Expand All @@ -233,8 +236,12 @@ def extend_subscriptions(at_time=None, dry_run=False):
if (upper == subscription.ends_at
and (days_from_end >= 0 and days_from_end < 1)):
# We are in the last day of the last period.
LOGGER.info("EXTENDS subscription %s ending at %s for 1 period",
subscription, subscription.ends_at)
LOGGER.info("EXTENDS subscription %s ending at %s for %d %s",
subscription, subscription.ends_at,
subscription.plan.period_length, describe_period_name(
subscription.plan.period_type,
subscription.plan.period_length))
nb_renewals += 1
if not dry_run:
try:
with transaction.atomic():
Expand All @@ -247,6 +254,7 @@ def extend_subscriptions(at_time=None, dry_run=False):
LOGGER.exception(
"error: extending subscription for %s ending at %s: %s",
subscription, subscription.ends_at, err)
return nb_renewals


def trigger_expiration_notices(at_time=None, nb_days=15, dry_run=False):
Expand All @@ -255,6 +263,7 @@ def trigger_expiration_notices(at_time=None, nb_days=15, dry_run=False):
"""

def _handle_organization_notices(organization):
nb_notices = 0
if organization.processor_card_key:
card = organization.retrieve_card()
try:
Expand All @@ -264,6 +273,7 @@ def _handle_organization_notices(organization):
if lower >= exp_date:
LOGGER.info("payment method expires soon for %s",
organization)
nb_notices += 1
if not dry_run:
signals.card_expires_soon.send(
sender=__name__, organization=organization,
Expand All @@ -274,10 +284,13 @@ def _handle_organization_notices(organization):
else:
LOGGER.info("%s doesn't have a payment method attached",
organization)
nb_notices += 1
if not dry_run:
signals.payment_method_absent.send(sender=__name__,
organization=organization)
return nb_notices

nb_notices = 0
at_time = datetime_or_now(at_time)
lower = at_time + relativedelta(days=nb_days)
upper = at_time + relativedelta(days=nb_days + 1)
Expand All @@ -295,18 +308,20 @@ def _handle_organization_notices(organization):
if subscription.auto_renew:
if plan.renewal_type == plan.AUTO_RENEW:
if org.id != prev_organization:
_handle_organization_notices(org)
nb_notices += _handle_organization_notices(org)

prev_organization = org.id
else:
if plan.renewal_type == plan.ONE_TIME:
LOGGER.info("trigger upgrade soon for %s", subscription)
nb_notices += 1
if not dry_run:
signals.subscription_upgrade.send(sender=__name__,
subscription=subscription, nb_days=nb_days)

elif plan.renewal_type == plan.REPEAT:
LOGGER.info("trigger expires soon for %s", subscription)
nb_notices += 1
if not dry_run:
signals.expires_soon.send(sender=__name__,
subscription=subscription, nb_days=nb_days)
Expand All @@ -321,14 +336,17 @@ def _handle_organization_notices(organization):
if subscription and subscription.organization.id != prev_organization:
if subscription.auto_renew:
if subscription.plan.renewal_type == subscription.plan.AUTO_RENEW:
_handle_organization_notices(subscription.organization)
nb_notices += _handle_organization_notices(
subscription.organization)
return nb_notices


def create_charges_for_balance(until=None, dry_run=False):
"""
Create charges for all accounts payable.
"""
#pylint:disable=too-many-nested-blocks
nb_charges = 0
until = datetime_or_now(until)
LOGGER.info("create charges for balance at %s ...", until)
for organization in get_organization_model().objects.filter(
Expand Down Expand Up @@ -366,6 +384,7 @@ def create_charges_for_balance(until=None, dry_run=False):
if not organization.processor_card_key:
raise CardError(_("No payment method attached"),
'card_absent')
nb_charges += 1
if not dry_run:
Charge.objects.charge_card(
organization, invoiceables,
Expand Down Expand Up @@ -417,6 +436,7 @@ def create_charges_for_balance(until=None, dry_run=False):
else:
LOGGER.info('SKIP %s (one charge already in flight)',
organization)
return nb_charges


def complete_charges():
Expand Down

0 comments on commit 543dcca

Please sign in to comment.