from datetime import timedelta, date import pygal from .models import User from payments.models import BACKENDS from payments.models import Payment PERIOD_VERBOSE_NAME = { 'y': "per month", 'm': "per day", } def monthdelta(date, delta): m = (date.month + delta) % 12 y = date.year + (date.month + delta - 1) // 12 if not m: m = 12 d = min(date.day, [31, 29 if y % 4 == 0 and not y % 400 == 0 else 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ][m - 1]) return date.replace(day=d, month=m, year=y) def last_days(n=30): now = date.today() for i in range(n - 1, -1, -1): yield now - timedelta(days=i) def last_months(n=12): now = date.today().replace(day=1) for i in range(n - 1, -1, -1): yield monthdelta(now, -i) def time_filter_future(period, m, df): def _filter(o): if period == 'm': return df(o).date() <= m if period == 'y': return df(o).date().replace(day=1) <= m return _filter def time_filter_between(period, m, df): def _filter(o): if period == 'm': return df(o).year == m.year and df(o).month == m.month and df(o).day == m.day return df(o).date() <= m and df(o).date() > (m - timedelta(days=1)) if period == 'y': return df(o).year == m.year and df(o).month == m.month return (df(o).date().replace(day=1) <= m and df(o).date().replace(day=1) > (m - timedelta(days=30))) return _filter def users_graph(period): chart = pygal.Line(fill=True, x_label_rotation=75, show_legend=False) chart.title = 'Users %s' % PERIOD_VERBOSE_NAME[period] chart.x_labels = [] values = [] gen = last_days(30) if period == 'm' else last_months(12) users = User.objects.all() for m in gen: filter_ = time_filter_future(period, m, lambda o: o.date_joined) users_filtered = filter(filter_, users) values.append(len(list(users_filtered))) chart.x_labels.append('%02d/%02d' % (m.month, m.day)) chart.add('Users', values) return chart.render() def payments_paid_graph(period): chart = pygal.StackedBar(x_label_rotation=75, show_legend=True) chart.x_labels = [] gen = list(last_days(30) if period == 'm' else last_months(12)) chart.title = 'Payments %s in €' % (PERIOD_VERBOSE_NAME[period]) for m in gen: chart.x_labels.append('%02d/%02d' % (m.month, m.day)) values = dict() for backend_id, backend in BACKENDS.items(): values = [] payments = list(Payment.objects.filter(status='confirmed', backend_id=backend_id)) for m in gen: filter_ = time_filter_between(period, m, lambda o: o.created) filtered = filter(filter_, payments) values.append(sum(u.paid_amount for u in filtered) / 100) chart.add(backend_id, values) return chart.render() def payments_success_graph(period): chart = pygal.StackedBar(x_label_rotation=75, show_legend=True) chart.x_labels = [] gen = list(last_days(30) if period == 'm' else last_months(12)) chart.title = 'Successful payments %s' % (PERIOD_VERBOSE_NAME[period]) for m in gen: chart.x_labels.append('%02d/%02d' % (m.month, m.day)) values = dict() for backend_id, backend in BACKENDS.items(): values = [] payments = list(Payment.objects.filter(status='confirmed', backend_id=backend_id)) for m in gen: filter_ = time_filter_between(period, m, lambda o: o.created) filtered = filter(filter_, payments) values.append(sum(1 for u in filtered)) chart.add(backend_id, values) return chart.render()