regluit/core/management/commands/campaign_data.py

171 lines
7.9 KiB
Python

from django.core.management.base import BaseCommand
import django
from regluit.core.models import Campaign
from regluit.payment.models import Transaction
from django.db.models import Q, F, Count, Sum, Max
from django.contrib.auth.models import User
from regluit.payment.manager import PaymentManager
from decimal import Decimal as D
from regluit.experimental.gutenberg import unicode_csv
def amazon_payments(fname=r"/Users/raymondyee/Downloads/All-Activity-Jan-01-2012-Jul-17-2012.csv"):
r0 = unicode_csv.UnicodeReader(f=open(fname), encoding="iso-8859-1")
# grab the header
header = r0.next()
print "header", header
r = unicode_csv.UnicodeDictReader(f=open(fname), fieldnames=header, encoding="iso-8859-1")
return dict([(k['Transaction ID'],k) for k in r])
def transactions_with_payment_info(transactions, payments=None):
"""an iterator for transactions / if a dict representing the actual payment data is provided, correlate the two"""
for t in transactions:
data = {"id": t.id,
"user_id": t.user.id,
"username":t.user.username,
"email":t.user.email,
"campaign_id": t.campaign.id if t.campaign is not None else "NULL",
"amount":t.amount,
"status":t.status,
"local_status":t.local_status,
"premium_id": t.premium.id if t.premium is not None else "NULL",
"premium_amount": t.premium.amount if t.premium is not None else "NULL",
"premium_description": t.premium.description if t.premium is not None else "NULL",
"preapproval_key":t.preapproval_key,
"approved":t.approved,
"error":t.error}
if payments is not None:
payment = payments.get(t.preapproval_key, None)
if payment is not None:
data.update({'payment_transaction_id':payment['Transaction ID'],
'payment_name': payment['Name'],
'payment_status': payment['Status'],
'payment_amount': D(payment['Amount'].replace("$","")),
'payment_fees': D(payment['Fees'].replace("$",""))
})
else:
data.update({'payment_transaction_id':"NULL",
'payment_name': "NULL",
'payment_status': "NULL",
'payment_amount': "NULL",
'payment_fees': "NULL"
})
else:
data.update({'payment_transaction_id':"NULL",
'payment_name': "NULL",
'payment_status': "NULL",
'payment_amount': "NULL",
'payment_fees': "NULL"
})
yield data
def stats_for_campaign(c):
print "transactions by statuses", c.transaction_set.values('status').annotate(count_status=Count('status'))
# distinguish among campaigns that are Active, Successful, or Closed
if c.status == 'ACTIVE':
# nothing collected yet -- can tally all Active transactions for a total
valid_trans = c.transaction_set.filter(Q(status='Complete') | Q(status='Active') | Q(status='Pending') | Q(status='Error') | Q(status='Failed') )
total_amount = c.transaction_set.filter(Q(status='Active')).aggregate(Sum('amount'))['amount__sum']
print "expected amount for active campaign", total_amount
elif c.status == 'SUCCESSFUL':
# how to not double count transactions wih Error or Failed status that have an Active or Completed followup?
valid_trans = c.transaction_set.filter(Q(status='Complete') | Q(status='Active') )
uid_ok_trans = set([x[0] for x in c.transaction_set.filter(Q(status='Complete') | Q(status='Active')).values_list('user')])
cleared_amount = c.transaction_set.filter(Q(status='Complete')).aggregate(Sum('amount'))['amount__sum']
failed_errored_amount = sum([t.amount for t in c.transaction_set.filter(Q(status='Pending') | Q(status='Error') | Q(status='Failed') ) if t.user.id not in uid_ok_trans])
print "cleared amount for Successful campaign", cleared_amount
print "failed_errored_amount for Successful campaign", failed_errored_amount
elif c.status == 'CLOSED':
valid_trans = c.transaction_set.filter(Q(status='Complete'))
total_amount = c.transaction_set.filter(Q(status='Complete')).aggregate(Sum('amount'))['amount__sum']
print "total amount for Closed campaign", total_amount
else:
valid_trans = c.transaction_set.filter(Q(status='Complete') | Q(status='Active') | Q(status='Pending') | Q(status='Error') | Q(status='Failed') )
# distribution?
clusters = valid_trans.values('amount').annotate(count_amount=Count('amount')).order_by('-amount')
for t in clusters:
print "{0}\t{1}\t{2}".format(t['amount'], t['count_amount'], t['count_amount']*t['amount'])
c_users = set([u[0] for u in c.transaction_set.values_list('user__username')])
# 0 or 1 Active
# 0 or 1 Complete
# Created? -- outmoded
# any number of NONE
# any number of Canceled
# if there is an Active transaction, it should be the very last one.
c_users_active_t = set([u[0] for u in c.transaction_set.filter(status='Active').values_list('user__username')])
[(u, c.transaction_set.filter(user__username=u).values_list('status').order_by('-date_created')[0]) for u in c_users_active_t]
# pull up latest transaction by user
# is there only one and only one active transaction for a user who has pledged?
# users who have more than one transaction with c
users_multi_trans = c.transaction_set.values_list('user__username').annotate(user_count=Count('user')).filter(user_count__gt=1)
# NONE status -- follow up on?
# tally up different classes of statuses we have for c
# who has modified a transaction and never cancelled it?
class Command(BaseCommand):
help = "Displays data about how the campaigns are progressing"
# args = "<filename> <username>"
def handle(self, **options):
# what campaigns are active
# List the campaigns
for c in Campaign.objects.all():
print c.name, c.status
print
# tally up the number of Campaigns with various statuses
print Campaign.objects.values('status').annotate(count_status=Count('status'))
print
# breakdown of Transactions by status
print "transactions by status", Transaction.objects.values('status').annotate(count_status=Count('status'))
print
# distribution of donations for *Oral Literature*
print "stats for *Oral Literature in Africa*"
c3 = Campaign.objects.get(id=3)
stats_for_campaign(c3)
out_fname = "/Users/raymondyee/Downloads/unglue_it_trans.csv"
out_headers = ["id",
"user_id",
"username",
"email",
"campaign_id",
"amount",
"status",
"local_status",
"premium_id",
"premium_amount",
"premium_description",
"preapproval_key",
"approved",
"error",
"payment_transaction_id",
"payment_name",
"payment_fees",
"payment_status",
"payment_amount"
]
f = open(out_fname, "wb")
transactions = c3.transaction_set.filter(Q(status='Complete') | Q(status='Active') | Q(status='Pending') | Q(status='Error') | Q(status='Failed') )
f = unicode_csv.output_to_csv(f, out_headers, transactions_with_payment_info(transactions, payments = amazon_payments()))