Merge branch 'expiring_cc' of github.com:Gluejar/regluit into expiring_cc

pull/1/head
Raymond Yee 2013-08-08 12:28:36 -04:00
commit 27bc134fa4
10 changed files with 357 additions and 138 deletions

View File

@ -13,7 +13,6 @@ django imports
from django.conf import settings
from django.contrib.auth.models import User
from django.core.mail import send_mail
from django.db.models import Q
from notification.engine import send_all
from notification import models as notification
@ -29,8 +28,6 @@ from regluit.core import (
from regluit.core.models import Campaign
from regluit.core.signals import deadline_impending
from regluit.payment.models import Account
from regluit.utils.localdatetime import now, date_today
logger = logging.getLogger(__name__)
@ -99,60 +96,6 @@ def update_active_campaign_status():
"""update the status of all active campaigns -- presumed to be run at midnight Eastern time"""
return [c.update_status(send_notice=True, ignore_deadline_for_success=True, process_transactions=True) for c in Campaign.objects.filter(status='Active') ]
#task to update the status of accounts
@task
def update_account_status(all_accounts=True):
"""update the status of all Accounts"""
errors = []
if all_accounts:
accounts_to_calc = Account.objects.all()
else:
# active accounts with expiration dates from this month earlier
today = date_today()
year = today.year
month = today.month
accounts_to_calc = Account.objects.filter(Q(date_deactivated__isnull=True)).filter((Q(card_exp_year__lt=year) | Q(card_exp_year=year, card_exp_month__lte = month)))
for account in accounts_to_calc:
try:
account.update_status()
except Exception, e:
errors.append(e)
# fire off notices
from regluit.core.tasks import emit_notifications
emit_notifications.delay()
return errors
# task run roughly 8 days ahead of card expirations
@task
def notify_expiring_accounts():
from regluit.payment.models import Account
from django.contrib.sites.models import Site
expiring_accounts = Account.objects.filter(status='EXPIRING')
for account in expiring_accounts:
notification.send_now([account.user], "account_expiring", {
'user': account.user,
'site':Site.objects.get_current()
}, True)
# used for bootstrapping our expired cc notification for first time
@task
def notify_expired_accounts():
from regluit.payment.models import Account
from django.contrib.sites.models import Site
expired_accounts = Account.objects.filter(status='EXPIRED')
for account in expired_accounts:
notification.send_now([account.user], "account_expired", {
'user': account.user,
'site':Site.objects.get_current()
}, True)
@task
def emit_notifications():
logger.info('notifications emitting' )

View File

@ -8,5 +8,5 @@ The current card we have on file:
Card type: {{ user.profile.account.card_type }}
Number: ************{{ user.profile.account.card_last4 }}
Expiration date: {{ user.profile.account.card_exp_month }}/{{ user.profile.account.card_exp_year }}.
We use Stripe< to keep your information secure.
We use Stripe to keep your information secure.
{% endif %}

View File

@ -10,7 +10,7 @@ The current card we have on file:
Card type: {{ user.profile.account.card_type }}
Number: ************{{ user.profile.account.card_last4 }}
Expiration date: {{ user.profile.account.card_exp_month }}/{{ user.profile.account.card_exp_year }}.
We use Stripe< to keep your information secure.
We use Stripe to keep your information secure.
{% endif %}

View File

@ -10,5 +10,5 @@ The current card we have on file:
Card type: {{ user.profile.account.card_type }}
Number: ************{{ user.profile.account.card_last4 }}
Expiration date: {{ user.profile.account.card_exp_month }}/{{ user.profile.account.card_exp_year }}.
We use Stripe< to keep your information secure.
We use Stripe to keep your information secure.
{% endif %}

View File

@ -25,7 +25,8 @@
],
"language": "python",
"metadata": {},
"outputs": []
"outputs": [],
"prompt_number": 1
},
{
"cell_type": "code",
@ -38,7 +39,16 @@
],
"language": "python",
"metadata": {},
"outputs": []
"outputs": [
{
"output_type": "pyout",
"prompt_number": 2,
"text": [
"datetime.date(2013, 8, 5)"
]
}
],
"prompt_number": 2
},
{
"cell_type": "heading",
@ -101,7 +111,21 @@
],
"language": "python",
"metadata": {},
"outputs": []
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"number of active accounts 190\n",
"expired: 17 expiring: 5 expire later: 168\n",
"expiring soon\n",
"[(<User: ALewis>, 8L, 2013L), (<User: CrisGee>, 8L, 2013L), (<User: pbelang>, 8L, 2013L), (<User: edsu>, 8L, 2013L), (<User: LucaF>, 8L, 2013L)]\n",
"expired\n",
"[(<User: benkeele>, 7L, 2013L), (<User: librarianry>, 2L, 2013L), (<User: aprcunningham>, 7L, 2013L), (<User: ZanRosin>, 7L, 2013L), (<User: rlitwin>, 6L, 2013L), (<User: nblack72649267>, 6L, 2013L), (<User: chjones>, 7L, 2013L), (<User: ranti>, 1L, 2013L), (<User: stellans>, 6L, 2013L), (<User: BillBrowne>, 2L, 2013L), (<User: stigkj>, 2L, 2013L), (<User: AndreaKosavic>, 4L, 2013L), (<User: TerryGammon>, 7L, 2013L), (<User: KateGukeisen>, 7L, 2013L), (<User: DanScott>, 4L, 2013L), (<User: helrond>, 7L, 2013L), (<User: DreamWithMe>, 6L, 2013L)]\n"
]
}
],
"prompt_number": 3
},
{
"cell_type": "code",
@ -125,7 +149,27 @@
],
"language": "python",
"metadata": {},
"outputs": []
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"(<User: benkeele>, 7L, 2013L)\n",
"(<User: aprcunningham>, 7L, 2013L)\n",
"(<User: ZanRosin>, 7L, 2013L)\n",
"(<User: ALewis>, 8L, 2013L)\n",
"(<User: CrisGee>, 8L, 2013L)\n",
"(<User: chjones>, 7L, 2013L)\n",
"(<User: TerryGammon>, 7L, 2013L)\n",
"(<User: KateGukeisen>, 7L, 2013L)\n",
"(<User: helrond>, 7L, 2013L)\n",
"(<User: pbelang>, 8L, 2013L)\n",
"(<User: edsu>, 8L, 2013L)\n",
"(<User: LucaF>, 8L, 2013L)\n"
]
}
],
"prompt_number": 4
},
{
"cell_type": "code",
@ -141,18 +185,28 @@
],
"language": "python",
"metadata": {},
"outputs": []
"outputs": [
{
"output_type": "pyout",
"prompt_number": 5,
"text": [
"[<Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, '...(remaining elements truncated)...']"
]
}
],
"prompt_number": 5
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from regluit.core import tasks\n",
"from regluit.payment import tasks\n",
"k = tasks.update_account_status.apply(args=[False])"
],
"language": "python",
"metadata": {},
"outputs": []
"outputs": [],
"prompt_number": 6
},
{
"cell_type": "code",
@ -162,7 +216,16 @@
],
"language": "python",
"metadata": {},
"outputs": []
"outputs": [
{
"output_type": "pyout",
"prompt_number": 7,
"text": [
"[]"
]
}
],
"prompt_number": 7
},
{
"cell_type": "code",
@ -175,7 +238,17 @@
],
"language": "python",
"metadata": {},
"outputs": []
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"[(<User: ALewis>, u'alewis4722@verizon.net', []), (<User: CrisGee>, u'bookish37@gmail.com', []), (<User: pbelang>, u'pbelang@uwindsor.ca', []), (<User: edsu>, u'ed.summers@gmail.com', []), (<User: LucaF>, u'lurikfa@gmail.com', [])]\n",
"[(<User: benkeele>, u'benjamin.j.keele@gmail.com', []), (<User: librarianry>, u'rclaringbole@gmail.com', []), (<User: aprcunningham>, u'aprcunningham@gmail.com', []), (<User: ZanRosin>, u'zanrosin@gmail.com', []), (<User: rlitwin>, u'rlitwin@gmail.com', []), (<User: nblack72649267>, u'nblack726@aol.com', []), (<User: chjones>, u'chjones@aleph0.com', []), (<User: ranti>, u'ranti.junus@gmail.com', []), (<User: stellans>, u'stellans@gmail.com', []), (<User: BillBrowne>, u'williamgeorgebrowne@gmail.com', []), (<User: stigkj>, u'stigkj@gmail.com', []), (<User: AndreaKosavic>, u'akosavic@gmail.com', []), (<User: TerryGammon>, u'terry.gammon@gmail.com', []), (<User: KateGukeisen>, u'kegukeis@syr.edu', []), (<User: DanScott>, u'dan@coffeecode.net', []), (<User: helrond>, u'hillel.arnold@gmail.com', []), (<User: DreamWithMe>, u'astanton@booklamp.org', [])]\n"
]
}
],
"prompt_number": 6
},
{
"cell_type": "code",
@ -199,7 +272,16 @@
],
"language": "python",
"metadata": {},
"outputs": []
"outputs": [
{
"output_type": "pyout",
"prompt_number": 7,
"text": [
"[]"
]
}
],
"prompt_number": 7
},
{
"cell_type": "code",
@ -209,7 +291,16 @@
],
"language": "python",
"metadata": {},
"outputs": []
"outputs": [
{
"output_type": "pyout",
"prompt_number": 8,
"text": [
"[<Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>, <Account: Account object>]"
]
}
],
"prompt_number": 8
},
{
"cell_type": "heading",
@ -230,44 +321,68 @@
],
"language": "python",
"metadata": {},
"outputs": []
"outputs": [],
"prompt_number": 9
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from django.contrib.auth.models import User\n",
"ry = User.objects.get(email = 'raymond.yee@gmail.com')"
"from django.conf import settings\n",
"me = User.objects.get(email = settings.EMAIL_HOST_USER )"
],
"language": "python",
"metadata": {},
"outputs": []
"outputs": [],
"prompt_number": 10
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"notification.send_now([ry], \"account_expiring\", {\n",
" 'user': ry, \n",
" 'site':Site.objects.get_current()\n",
" }, True)"
"print me, settings.EMAIL_HOST"
],
"language": "python",
"metadata": {},
"outputs": []
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"eric smtp.gmail.com\n"
]
}
],
"prompt_number": 11
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"notification.send_now([ry], \"account_expired\", {\n",
" 'user': ry, \n",
"notification.send_now([me], \"account_expiring\", {\n",
" 'user': me, \n",
" 'site':Site.objects.get_current()\n",
" }, True)"
],
"language": "python",
"metadata": {},
"outputs": []
"outputs": [],
"prompt_number": 12
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"notification.send_now([me], \"account_expired\", {\n",
" 'user': me, \n",
" 'site':Site.objects.get_current()\n",
" }, True)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 14
},
{
"cell_type": "heading",

View File

@ -1,27 +1,48 @@
# -*- coding: utf-8 -*-
# <nbformat>3.0</nbformat>
# <markdowncell>
# # working out logic around expiring credit cards
# In[ ]:
# <codecell>
from regluit.payment.stripelib import StripeClient
from regluit.payment.models import Account
from django.db.models import Q, F
# <codecell>
### expiring, expired, soon to expire cards
# use the localdatetime?
from regluit.utils import localdatetime
localdatetime.date_today()
# <headingcell level=2>
# expiring, expired, soon to expire cards
# <codecell>
# In[ ]:
from regluit.payment.models import Account
from django.db.models import Q
import datetime
from dateutil.relativedelta import relativedelta
# set the month/year for comparison
#
# # http://stackoverflow.com/a/15155212/7782
today = datetime.date.today()
year = today.year
month = today.month
date_before_month = today + relativedelta(months=-1)
year_last_month = date_before_month.year
month_last_month = date_before_month.month
#year = 2013
#month = 2
@ -51,13 +72,52 @@ print [(account.user, account.card_exp_month, account.card_exp_year) for account
print "expired"
print [(account.user, account.card_exp_month, account.card_exp_year) for account in accounts_expired]
# In[ ]:
# <codecell>
# looking at filtering Accounts that might expire
# if the the month of the expiration date == next month or earlier
# accounts with expiration of this month and last month -- and to be more expansive filter: expiration with this month or before
# also Account.objects.filter(Q(date_deactivated__isnull=True))
#
# accounts_expired = active_accounts.filter((Q(card_exp_year__lt=year) | Q(card_exp_year=year, card_exp_month__lt = month)))
accounts_to_consider_expansive = Account.objects.filter(Q(date_deactivated__isnull=True)).filter((Q(card_exp_year__lt=year) | Q(card_exp_year=year, card_exp_month__lte = month)))
# this month or last last monthj
accounts_to_consider_narrow = Account.objects.filter(Q(date_deactivated__isnull=True)).filter(Q(card_exp_year=year, card_exp_month = month) | Q(card_exp_year=year_last_month, card_exp_month = month_last_month))
for account in accounts_to_consider_narrow:
print (account.user, account.card_exp_month, account.card_exp_year)
# <codecell>
from regluit.utils.localdatetime import date_today
today = date_today()
year = today.year
month = today.month
accounts_to_calc = Account.objects.filter(Q(date_deactivated__isnull=True)).filter((Q(card_exp_year__lt=year) | Q(card_exp_year=year, card_exp_month__lte = month)))
accounts_to_calc
# <codecell>
from regluit.payment import tasks
k = tasks.update_account_status.apply(args=[False])
# <codecell>
k.get()
# <codecell>
# list any active transactions tied to users w/ expiring and expired CC?
print [(account.user, account.user.email, [t.campaign for t in account.user.transaction_set.filter(status='ACTIVE')]) for account in accounts_expiring]
print [(account.user, account.user.email, [t.campaign for t in account.user.transaction_set.filter(status='ACTIVE')]) for account in accounts_expired]
# In[ ]:
# <codecell>
# more to the point, what cards have expired or will expire by the time we have a hopefully
# successful close for Feeding the City (campaign # 15)?
@ -74,37 +134,51 @@ ftc_expired_accounts = [User.objects.get(id=supporter_id).profile.account for su
User.objects.get(id=supporter_id).profile.account.status == 'EXPIRING']
ftc_expired_accounts
# <codecell>
# In[ ]:
Account.objects.filter(status='EXPIRED')
## coming up with good notices to send out
# <headingcell level=1>
# coming up with good notices to send out
# <codecell>
# In[ ]:
from notification.engine import send_all
from notification import models as notification
from django.contrib.sites.models import Site
# In[ ]:
# <codecell>
from django.contrib.auth.models import User
ry = User.objects.get(email = 'raymond.yee@gmail.com')
from django.conf import settings
me = User.objects.get(email = settings.EMAIL_HOST_USER )
# In[ ]:
notification.send_now([ry], "account_expiring", {
'user': ry,
# <codecell>
print me, settings.EMAIL_HOST
# <codecell>
notification.send_now([me], "account_expiring", {
'user': me,
'site':Site.objects.get_current()
}, True)
# In[ ]:
notification.send_now([ry], "account_expired", {
'user': ry,
# <codecell>
notification.send_now([me], "account_expired", {
'user': me,
'site':Site.objects.get_current()
}, True)
## accounts with problem transactions
# <headingcell level=1>
# accounts with problem transactions
# <codecell>
# In[ ]:
# easy to figure out the card used for a specific problem transaction?
# want to figure out problem status for a given Account
@ -116,6 +190,8 @@ from regluit.payment.models import Transaction
Transaction.objects.filter(host='stripelib', status='Error', approved=True).count()
# <markdowncell>
# I am hoping that we can use the API to ask for a list of charge.failed --> but I don't see a way to query charges based upon on the status of the charges -- what you have to iterate through all of the charges and filter based on status. ( maybe I should confirm this fact with people at stripe) -- ok let's do that for now.
#
# **Note: One needs to have productionstripe keys loaded in database to run following code**
@ -124,7 +200,8 @@ Transaction.objects.filter(host='stripelib', status='Error', approved=True).coun
#
# `/Volumes/ryvault1/gluejar/stripe/set_stripe_keys.py`
# In[ ]:
# <codecell>
from regluit.payment.stripelib import StripeClient
from regluit.payment.models import Transaction
@ -141,12 +218,16 @@ print failed_charges
print [t.status for t in Transaction.objects.filter(id__in = [fc[3] for fc in failed_charges])]
# <headingcell level=2>
### Work to create an Account.account_status()
# Work to create an Account.account_status()
# <markdowncell>
# First working out conditions for **ERROR** status
# In[ ]:
# <codecell>
# acc_with_error = transaction # 773 -- the one with an Error that we wrote off
acc_with_error = Transaction.objects.get(id=773).user.profile.account
@ -166,9 +247,12 @@ acc_with_error.date_created, [t.date_payment for t in trans]
print trans.filter(date_payment__gt=acc_with_error.date_created)
# <markdowncell>
# https://github.com/Gluejar/regluit/commit/c3f922e9ba61bc412657cfa18c7d8f8d3df6eb38#L1R341 --> it's made its way into the unglue.it code, at least in the `expiring_cc` branch
# In[ ]:
# <codecell>
# Given the specific account I would like to cut the status... need to handle expiration as well as declined charges
from regluit.payment.models import Transaction
@ -208,7 +292,8 @@ def account_status(account):
return 'ACTIVE'
# In[ ]:
# <codecell>
# test out with the account that is currently erroring out
acc_with_error = Transaction.objects.get(id=773).user.profile.account
@ -216,9 +301,12 @@ print account_status(acc_with_error)
print
acc_with_error.status
# <markdowncell>
# # validity of accounts -- need to use real stripe keys if we want to look at production data
# In[ ]:
# <codecell>
from regluit.payment.stripelib import StripeClient
from django.db.models import Q
@ -231,10 +319,12 @@ customers = list(sc._all_objs('Customer'))
customer.active_card.get("address_zip_check"),
customer.active_card.get("cvc_check")) for customer in customers if customer.active_card is not None]
# <markdowncell>
# # look at only customers that are attached to active Account
# In[ ]:
# <codecell>
from regluit.payment.stripelib import StripeClient
from regluit.payment.models import Account
@ -245,22 +335,25 @@ active_accounts = Account.objects.filter(Q(date_deactivated__isnull=True))
active_customer_ids = set([account.account_id for account in active_accounts])
# <codecell>
# In[ ]:
[(customer.active_card["address_line1_check"],
customer.active_card["address_zip_check"],
customer.active_card["cvc_check"]) for customer in customers if customer.id in active_customer_ids]
# <markdowncell>
# # handling campaign totals properly based on account statuses
#
# **Will we need to start marking accounts as expired explicitly?**
#
# add a manager method?
#
# In[ ]:
# <codecell>
# calculate which active transactions not tied to an active account w/ unexpired CC
# <markdowncell>
# # should we delete stripe accounts associated with deactivated accounts -- I think yes
#
@ -269,8 +362,11 @@ customer.active_card["cvc_check"]) for customer in customers if customer.id in a
# * clean up Customer associated with current deactivated accounts
# * build logic in to delete Customer once the correspending account are deactivated and we safely have a new Account/Customer in place -- maybe a good task to put into the webhook handler
# In[ ]:
# <codecell>
len(active_customer_ids)
# In[ ]:
# <codecell>
# do the users w/ deactivated accounts have active ones?

View File

@ -364,6 +364,7 @@ class Account(models.Model):
def deactivate(self):
"""Don't allow more than one active Account of given host to be associated with a given user"""
self.date_deactivated = now()
self.status = 'DEACTIVATED'
self.save()
def calculated_status(self):
@ -396,7 +397,7 @@ class Account(models.Model):
return 'ACTIVE'
def update_status(value=None):
def update_status( self, value=None):
"""set Account.status = value unless value is None, in which case, we set Account.status=self.calculated_status()
fire off associated notifications
"""
@ -443,6 +444,21 @@ class Account(models.Model):
# nothing needs to happen here
pass
def recharge_failed_transactions(self):
"""When a new Account is saved, check whether this is the new active account for a user. If so, recharge any
outstanding failed transactions
"""
transactions_to_recharge = self.user.transaction_set.filter((Q(status=TRANSACTION_STATUS_FAILED) | Q(status=TRANSACTION_STATUS_ERROR)) & Q(campaign__status='SUCCESSFUL')).all()
if transactions_to_recharge:
from regluit.payment.manager import PaymentManager
pm = PaymentManager()
for transaction in transactions_to_recharge:
# check whether we are still within the window to recharge
if (now() - transaction.campaign.deadline) < datetime.timedelta(settings.RECHARGE_WINDOW):
logger.info("Recharging transaction {0} w/ status {1}".format(transaction.id, transaction.status))
pm.execute_transaction(transaction, [])
# handle any save, updates to a payment.Transaction
@ -465,25 +481,4 @@ post_delete.connect(handle_transaction_delete,sender=Transaction)
# handle recharging failed transactions
def recharge_failed_transactions(sender, created, instance, **kwargs):
"""When a new Account is saved, check whether this is the new active account for a user. If so, recharge any
outstanding failed transactions
"""
# make sure the new account is active
if instance.date_deactivated is not None:
return False
transactions_to_recharge = instance.user.transaction_set.filter((Q(status=TRANSACTION_STATUS_FAILED) | Q(status=TRANSACTION_STATUS_ERROR)) & Q(campaign__status='SUCCESSFUL')).all()
if transactions_to_recharge:
from regluit.payment.manager import PaymentManager
pm = PaymentManager()
for transaction in transactions_to_recharge:
# check whether we are still within the window to recharge
if (now() - transaction.campaign.deadline) < datetime.timedelta(settings.RECHARGE_WINDOW):
logger.info("Recharging transaction {0} w/ status {1}".format(transaction.id, transaction.status))
pm.execute_transaction(transaction, [])
post_save.connect(recharge_failed_transactions, sender=Account)

View File

@ -591,6 +591,9 @@ class Processor(baseprocessor.Processor):
if user.profile.account:
user.profile.account.deactivate()
account.save()
account.recharge_failed_transactions()
else:
account.save()
return account
class Preapproval(StripePaymentRequest, baseprocessor.Processor.Preapproval):

67
payment/tasks.py Normal file
View File

@ -0,0 +1,67 @@
"""
external library imports
"""
from celery.task import task
"""
django imports
"""
from django.contrib.sites.models import Site
from django.db.models import Q
from notification import models as notification
"""
regluit imports
"""
from regluit.payment.models import Account
from regluit.utils.localdatetime import date_today
#task to update the status of accounts
@task
def update_account_status(all_accounts=True):
"""update the status of all Accounts"""
errors = []
if all_accounts:
accounts_to_calc = Account.objects.all()
else:
# active accounts with expiration dates from this month earlier
today = date_today()
year = today.year
month = today.month
accounts_to_calc = Account.objects.filter(Q(date_deactivated__isnull=True)).filter((Q(card_exp_year__lt=year) | Q(card_exp_year=year, card_exp_month__lte = month)))
for account in accounts_to_calc:
try:
account.update_status()
except Exception, e:
errors.append(e)
# fire off notices
from regluit.core.tasks import emit_notifications
emit_notifications.delay()
return errors
# task run roughly 8 days ahead of card expirations
@task
def notify_expiring_accounts():
expiring_accounts = Account.objects.filter(status='EXPIRING')
for account in expiring_accounts:
notification.send_now([account.user], "account_expiring", {
'user': account.user,
'site':Site.objects.get_current()
}, True)
# used for bootstrapping our expired cc notification for first time
@task
def notify_expired_accounts():
expired_accounts = Account.objects.filter(status='EXPIRED')
for account in expired_accounts:
notification.send_now([account.user], "account_expired", {
'user': account.user,
'site':Site.objects.get_current()
}, True)

View File

@ -311,13 +311,13 @@ NOTIFY_ENDING_SOON_JOB = {
}
UPDATE_ACCOUNT_STATUSES = {
"task": "regluit.core.tasks.update_account_status",
"task": "regluit.payment.tasks.update_account_status",
"schedule": crontab(day_of_month=1, hour=0, minute=0),
"args": ()
}
NOTIFY_EXPIRING_ACCOUNTS = {
"task": "regluit.core.tasks.notify_expiring_accounts",
"task": "regluit.payment.tasks.notify_expiring_accounts",
"schedule": crontab(day_of_month=22, hour=0, minute=30),
"args": ()
}