regluit/not_maintained/campaign_data.py

171 lines
7.9 KiB
Python

from decimal import Decimal as D
import django
from django.core.management.base import BaseCommand
from django.contrib.auth.models import User
from django.db.models import Q, F, Count, Sum, Max
from regluit.core.models import Campaign
from regluit.experimental.gutenberg import unicode_csv
from regluit.payment.models import Transaction
from regluit.payment.manager import PaymentManager
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()))