From 6ab6441e1455778dee0ada8d4b0d8edf0f072976 Mon Sep 17 00:00:00 2001 From: Denver Gingerich Date: Thu, 25 Jan 2018 10:59:18 -0500 Subject: [PATCH] python: report front-end for returning supporters A reporting script similar to status_report.py that uses the new returning supporter method (added in 7aaba96) to provide a list of how many supporters have started supporting again after lapsing, bucketed by the number of months for which they had been lapsed. --- python/returning_report.py | 71 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100755 python/returning_report.py diff --git a/python/returning_report.py b/python/returning_report.py new file mode 100755 index 0000000..024585f --- /dev/null +++ b/python/returning_report.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 + +import argparse +import collections +import csv +import datetime +import functools +import os +import sys + +import django + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'supporters.settings') +django.setup() +from supporters.models import Date, Payment, Supporter + +MONTH_FMT = '%Y-%m' + +def parse_arguments(arglist): + parser = argparse.ArgumentParser( + prog='returning_report', + description="Print a CSV report showing Supporters who returned", + ) + month_date = functools.partial(Date.strptime, fmt=MONTH_FMT) + parser.add_argument( + '--start-month', type=month_date, metavar='YYYY-MM', + default=Payment.objects.order_by('date').first().date, + help="First month in report") + parser.add_argument( + '--end-month', type=month_date, metavar='YYYY-MM', + default=Date.today(), + help="Last month in report") + args = parser.parse_args(arglist) + if args.end_month < args.start_month: + parser.error("End month predates start month") + return args + +def report_month(month): + annuals = collections.Counter(Supporter(name).status(month) + for name in Supporter.iter_entities(['Annual'])) + monthlies = collections.Counter(Supporter(name).status(month) + for name in Supporter.iter_entities(['Monthly'])) + eannuals = collections.Counter(Supporter(name).months_expired(month) + for name in Supporter.iter_entities(['Annual'])) + emonthlies = collections.Counter(Supporter(name).months_expired(month) + for name in Supporter.iter_entities(['Monthly'])) + return ((month.strftime(MONTH_FMT),) + + ((annuals + monthlies)[Supporter.STATUS_NEW],) + + ((eannuals + emonthlies)[Supporter.RETURNING_0MO],) + + ((eannuals + emonthlies)[Supporter.RETURNING_3MO],) + + ((eannuals + emonthlies)[Supporter.RETURNING_6MO],) + + ((eannuals + emonthlies)[Supporter.RETURNING_9MO],) + + ((eannuals + emonthlies)[Supporter.RETURNING_12MO],)) + +def main(arglist): + args = parse_arguments(arglist) + out_csv = csv.writer(sys.stdout) + # NOTE: 'Total New' here is the same as 'Total New' from status_report.py + out_csv.writerow(( + 'Month', + 'Total New', + 'Were 0-3mo expired', 'Were 3-6mo expired', 'Were 6-9mo expired', + 'Were 9-12mo expired', 'Were >1yr expired' + )) + month = Date.from_pydate(args.start_month) + while month <= args.end_month: + out_csv.writerow(report_month(month)) + month = month.round_month_up() + +if __name__ == '__main__': + main(None)