683 lines
23 KiB
Plaintext
683 lines
23 KiB
Plaintext
|
{
|
||
|
"metadata": {
|
||
|
"name": "expiring_stripe_cc"
|
||
|
},
|
||
|
"nbformat": 3,
|
||
|
"nbformat_minor": 0,
|
||
|
"worksheets": [
|
||
|
{
|
||
|
"cells": [
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"# working out logic around expiring credit cards"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"from regluit.payment.stripelib import StripeClient\n",
|
||
|
"from regluit.payment.models import Account\n",
|
||
|
"\n",
|
||
|
"from django.db.models import Q, F\n"
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"prompt_number": 1
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"# use the localdatetime?\n",
|
||
|
"\n",
|
||
|
"from regluit.utils import localdatetime\n",
|
||
|
"localdatetime.date_today()"
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"output_type": "pyout",
|
||
|
"prompt_number": 2,
|
||
|
"text": [
|
||
|
"datetime.date(2013, 8, 5)"
|
||
|
]
|
||
|
}
|
||
|
],
|
||
|
"prompt_number": 2
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "heading",
|
||
|
"level": 2,
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"expiring, expired, soon to expire cards"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"from regluit.payment.models import Account\n",
|
||
|
"from django.db.models import Q\n",
|
||
|
"import datetime\n",
|
||
|
"from dateutil.relativedelta import relativedelta\n",
|
||
|
"\n",
|
||
|
"\n",
|
||
|
"# set the month/year for comparison\n",
|
||
|
"\n",
|
||
|
"# # http://stackoverflow.com/a/15155212/7782\n",
|
||
|
"today = datetime.date.today()\n",
|
||
|
"year = today.year\n",
|
||
|
"month = today.month\n",
|
||
|
"\n",
|
||
|
"date_before_month = today + relativedelta(months=-1)\n",
|
||
|
"year_last_month = date_before_month.year\n",
|
||
|
"month_last_month = date_before_month.month\n",
|
||
|
"\n",
|
||
|
"\n",
|
||
|
"#year = 2013\n",
|
||
|
"#month = 2\n",
|
||
|
"\n",
|
||
|
"# look only at active accounts\n",
|
||
|
"\n",
|
||
|
"active_accounts = Account.objects.filter(Q(date_deactivated__isnull=True))\n",
|
||
|
"\n",
|
||
|
"# calculate expired cards\n",
|
||
|
"accounts_expired = active_accounts.filter((Q(card_exp_year__lt=year) | Q(card_exp_year=year, card_exp_month__lt = month)))\n",
|
||
|
"\n",
|
||
|
"# expiring on a given month\n",
|
||
|
"\n",
|
||
|
"accounts_expiring = active_accounts.filter(card_exp_year=year, card_exp_month = month)\n",
|
||
|
"\n",
|
||
|
"# yet to expire\n",
|
||
|
"\n",
|
||
|
"accounts_expiring_later = active_accounts.filter((Q(card_exp_year__gt=year) | Q(card_exp_year=year, card_exp_month__gt = month)))\n",
|
||
|
"\n",
|
||
|
"print \"number of active accounts\", active_accounts.count()\n",
|
||
|
"print \"expired: {0} expiring: {1} expire later: {2}\".format(accounts_expired.count(), accounts_expiring.count(), accounts_expiring_later.count())\n",
|
||
|
"\n",
|
||
|
"# expiring soon\n",
|
||
|
"print \"expiring soon\"\n",
|
||
|
"print [(account.user, account.card_exp_month, account.card_exp_year) for account in accounts_expiring]\n",
|
||
|
"\n",
|
||
|
"# expired\n",
|
||
|
"print \"expired\"\n",
|
||
|
"print [(account.user, account.card_exp_month, account.card_exp_year) for account in accounts_expired]"
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"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",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"# looking at filtering Accounts that might expire\n",
|
||
|
"\n",
|
||
|
"# if the the month of the expiration date == next month or earlier \n",
|
||
|
"# accounts with expiration of this month and last month -- and to be more expansive filter: expiration with this month or before\n",
|
||
|
"# also Account.objects.filter(Q(date_deactivated__isnull=True))\n",
|
||
|
"# \n",
|
||
|
"# accounts_expired = active_accounts.filter((Q(card_exp_year__lt=year) | Q(card_exp_year=year, card_exp_month__lt = month)))\n",
|
||
|
"\n",
|
||
|
"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)))\n",
|
||
|
"\n",
|
||
|
"# this month or last last monthj\n",
|
||
|
"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))\n",
|
||
|
"\n",
|
||
|
"for account in accounts_to_consider_narrow:\n",
|
||
|
" print (account.user, account.card_exp_month, account.card_exp_year) "
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"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",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"from regluit.utils.localdatetime import date_today\n",
|
||
|
"\n",
|
||
|
"today = date_today()\n",
|
||
|
"year = today.year\n",
|
||
|
"month = today.month\n",
|
||
|
"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)))\n",
|
||
|
"accounts_to_calc"
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"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.payment import tasks\n",
|
||
|
"k = tasks.update_account_status.apply(args=[False])"
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"prompt_number": 6
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"k.get()"
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"output_type": "pyout",
|
||
|
"prompt_number": 7,
|
||
|
"text": [
|
||
|
"[]"
|
||
|
]
|
||
|
}
|
||
|
],
|
||
|
"prompt_number": 7
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"# list any active transactions tied to users w/ expiring and expired CC?\n",
|
||
|
"\n",
|
||
|
"print [(account.user, account.user.email, [t.campaign for t in account.user.transaction_set.filter(status='ACTIVE')]) for account in accounts_expiring]\n",
|
||
|
"print [(account.user, account.user.email, [t.campaign for t in account.user.transaction_set.filter(status='ACTIVE')]) for account in accounts_expired]"
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"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",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"# more to the point, what cards have expired or will expire by the time we have a hopefully \n",
|
||
|
"# successful close for Feeding the City (campaign # 15)?\n",
|
||
|
"\n",
|
||
|
"from django.contrib.auth.models import User\n",
|
||
|
"from regluit.core.models import Campaign\n",
|
||
|
"\n",
|
||
|
"ftc_campaign = Campaign.objects.get(id=15)\n",
|
||
|
"\n",
|
||
|
"# get all accounts tied to this campaign....\n",
|
||
|
"len(ftc_campaign.supporters())\n",
|
||
|
"\n",
|
||
|
"ftc_expired_accounts = [User.objects.get(id=supporter_id).profile.account for supporter_id in ftc_campaign.supporters()\n",
|
||
|
" if User.objects.get(id=supporter_id).profile.account.status == 'EXPIRED' or \n",
|
||
|
" User.objects.get(id=supporter_id).profile.account.status == 'EXPIRING']\n",
|
||
|
"ftc_expired_accounts\n"
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"output_type": "pyout",
|
||
|
"prompt_number": 7,
|
||
|
"text": [
|
||
|
"[]"
|
||
|
]
|
||
|
}
|
||
|
],
|
||
|
"prompt_number": 7
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"Account.objects.filter(status='EXPIRED')"
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"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",
|
||
|
"level": 1,
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"coming up with good notices to send out "
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"from notification.engine import send_all\n",
|
||
|
"from notification import models as notification\n",
|
||
|
"\n",
|
||
|
"from django.contrib.sites.models import Site"
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"prompt_number": 9
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"from django.contrib.auth.models import User\n",
|
||
|
"from django.conf import settings\n",
|
||
|
"me = User.objects.get(email = settings.EMAIL_HOST_USER )"
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"prompt_number": 10
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"print me, settings.EMAIL_HOST"
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"output_type": "stream",
|
||
|
"stream": "stdout",
|
||
|
"text": [
|
||
|
"eric smtp.gmail.com\n"
|
||
|
]
|
||
|
}
|
||
|
],
|
||
|
"prompt_number": 11
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"notification.send_now([me], \"account_expiring\", {\n",
|
||
|
" 'user': me, \n",
|
||
|
" 'site':Site.objects.get_current()\n",
|
||
|
" }, True)"
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"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",
|
||
|
"level": 1,
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"accounts with problem transactions"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"# easy to figure out the card used for a specific problem transaction?\n",
|
||
|
"# want to figure out problem status for a given Account\n",
|
||
|
"\n",
|
||
|
"from regluit.payment.models import Transaction\n",
|
||
|
"\n",
|
||
|
"# Account has fingerprint\n",
|
||
|
"# transaction doesn't have fingerprint -- will have to calculate fingerprint of card associated with transaction\n",
|
||
|
"# w/ error if we store pay_key -- any problem?\n",
|
||
|
"\n",
|
||
|
"Transaction.objects.filter(host='stripelib', status='Error', approved=True).count()"
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"outputs": []
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"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.\n",
|
||
|
"\n",
|
||
|
"**Note: One needs to have productionstripe keys loaded in database to run following code**\n",
|
||
|
"\n",
|
||
|
"What script do I run to load these keys? \n",
|
||
|
"\n",
|
||
|
"`/Volumes/ryvault1/gluejar/stripe/set_stripe_keys.py`"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"from regluit.payment.stripelib import StripeClient\n",
|
||
|
"from regluit.payment.models import Transaction\n",
|
||
|
"\n",
|
||
|
"import json\n",
|
||
|
"from itertools import islice\n",
|
||
|
"\n",
|
||
|
"sc = StripeClient()\n",
|
||
|
"charges = islice(sc._all_objs('Charge'), None)\n",
|
||
|
"\n",
|
||
|
"failed_charges = [(c.amount, c.id, c.failure_message, json.loads(c.description)['t.id']) for c in charges if c.failure_message is not None]\n",
|
||
|
"print failed_charges\n",
|
||
|
"\n",
|
||
|
"# look up corresponding Transactions and flag the ones that have not been properly charged\n",
|
||
|
"\n",
|
||
|
"print [t.status for t in Transaction.objects.filter(id__in = [fc[3] for fc in failed_charges])]\n"
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"outputs": []
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "heading",
|
||
|
"level": 2,
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Work to create an Account.account_status()"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"First working out conditions for **ERROR** status"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"# acc_with_error = transaction # 773 -- the one with an Error that we wrote off\n",
|
||
|
"\n",
|
||
|
"acc_with_error = Transaction.objects.get(id=773).user.profile.account\n",
|
||
|
"acc_with_error.user\n",
|
||
|
"\n",
|
||
|
"# trans is all stripe transactions of user associated w/ acc_with_error\n",
|
||
|
"\n",
|
||
|
"trans = Transaction.objects.filter(host='stripelib', \n",
|
||
|
" status='Error', approved=True, user=acc_with_error.user)\n",
|
||
|
"\n",
|
||
|
"# comparing the transaction payment date with when account created.\n",
|
||
|
"# why? \n",
|
||
|
"# if account created after transaction payment date, we would want to retry the payment.\n",
|
||
|
"\n",
|
||
|
"\n",
|
||
|
"acc_with_error.date_created, [t.date_payment for t in trans] \n",
|
||
|
"\n",
|
||
|
"print trans.filter(date_payment__gt=acc_with_error.date_created)"
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"outputs": []
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"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"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"# Given the specific account I would like to cut the status... need to handle expiration as well as declined charges\n",
|
||
|
"\n",
|
||
|
"from regluit.payment.models import Transaction\n",
|
||
|
"from regluit.payment.models import Account\n",
|
||
|
"from regluit.utils.localdatetime import now, date_today\n",
|
||
|
"\n",
|
||
|
"from itertools import islice\n",
|
||
|
"\n",
|
||
|
"def account_status(account):\n",
|
||
|
"\n",
|
||
|
"# is it deactivated?\n",
|
||
|
"\n",
|
||
|
" today = date_today()\n",
|
||
|
" transactions_w_error_status_older_account = Transaction.objects.filter(host='stripelib', \n",
|
||
|
" status='Error', approved=True, user=account.user)\n",
|
||
|
" \n",
|
||
|
" if account.date_deactivated is not None:\n",
|
||
|
" return 'DEACTIVATED'\n",
|
||
|
"\n",
|
||
|
"# is it expired?\n",
|
||
|
"\n",
|
||
|
" elif account.card_exp_year < today.year or (account.card_exp_year == today.year and account.card_exp_month < today.month):\n",
|
||
|
" return 'EXPIRED'\n",
|
||
|
" \n",
|
||
|
"# about to expire? do I want to distinguish from 'ACTIVE'?\n",
|
||
|
"\n",
|
||
|
" elif (account.card_exp_year == today.year and account.card_exp_month == today.month):\n",
|
||
|
" return 'EXPIRING' \n",
|
||
|
"\n",
|
||
|
"# any transactions w/ errors after the account date?\n",
|
||
|
"# Transaction.objects.filter(host='stripelib', status='Error', approved=True).count()\n",
|
||
|
"\n",
|
||
|
" elif Transaction.objects.filter(host='stripelib', \n",
|
||
|
" status='Error', approved=True, user=account.user).filter(date_payment__gt=account.date_created):\n",
|
||
|
" return 'ERROR'\n",
|
||
|
" else:\n",
|
||
|
" return 'ACTIVE'\n",
|
||
|
" "
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"outputs": []
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"# test out with the account that is currently erroring out\n",
|
||
|
"\n",
|
||
|
"acc_with_error = Transaction.objects.get(id=773).user.profile.account\n",
|
||
|
"print account_status(acc_with_error)\n",
|
||
|
"print\n",
|
||
|
"acc_with_error.status"
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"outputs": []
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"# validity of accounts -- need to use real stripe keys if we want to look at production data"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"from regluit.payment.stripelib import StripeClient\n",
|
||
|
"from django.db.models import Q\n",
|
||
|
"\n",
|
||
|
"sc = StripeClient()\n",
|
||
|
"customers = list(sc._all_objs('Customer'))\n",
|
||
|
"\n",
|
||
|
"# 3 checks available to us: Address Line 1, zip code, CVC\n",
|
||
|
"\n",
|
||
|
"[(customer.id, customer.description, customer.active_card.get(\"address_line1_check\"), \n",
|
||
|
"customer.active_card.get(\"address_zip_check\"), \n",
|
||
|
"customer.active_card.get(\"cvc_check\")) for customer in customers if customer.active_card is not None]\n"
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"outputs": []
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"# look at only customers that are attached to active Account"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"from regluit.payment.stripelib import StripeClient\n",
|
||
|
"from regluit.payment.models import Account\n",
|
||
|
"\n",
|
||
|
"sc = StripeClient()\n",
|
||
|
"customers = sc._all_objs('Customer')\n",
|
||
|
"\n",
|
||
|
"active_accounts = Account.objects.filter(Q(date_deactivated__isnull=True))\n",
|
||
|
"\n",
|
||
|
"active_customer_ids = set([account.account_id for account in active_accounts])\n"
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"outputs": []
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"[(customer.active_card[\"address_line1_check\"], \n",
|
||
|
"customer.active_card[\"address_zip_check\"], \n",
|
||
|
"customer.active_card[\"cvc_check\"]) for customer in customers if customer.id in active_customer_ids]"
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"outputs": []
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"# handling campaign totals properly based on account statuses\n",
|
||
|
"\n",
|
||
|
"**Will we need to start marking accounts as expired explicitly?** \n",
|
||
|
"\n",
|
||
|
"add a manager method?\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"# calculate which active transactions not tied to an active account w/ unexpired CC\n"
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"outputs": []
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"# should we delete stripe accounts associated with deactivated accounts -- I think yes\n",
|
||
|
"\n",
|
||
|
"How to do? \n",
|
||
|
"\n",
|
||
|
"* clean up Customer associated with current deactivated accounts\n",
|
||
|
"* 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"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"len(active_customer_ids)"
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"outputs": []
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"collapsed": false,
|
||
|
"input": [
|
||
|
"# do the users w/ deactivated accounts have active ones?"
|
||
|
],
|
||
|
"language": "python",
|
||
|
"metadata": {},
|
||
|
"outputs": []
|
||
|
}
|
||
|
],
|
||
|
"metadata": {}
|
||
|
}
|
||
|
]
|
||
|
}
|