Account lookup summary data (bug 753979)

This commit is contained in:
Kumar McMillan 2012-05-25 16:55:19 -05:00
Родитель b709bd7802
Коммит 0f4250e638
5 изменённых файлов: 245 добавлений и 6 удалений

Просмотреть файл

@ -0,0 +1,13 @@
from jingo import register
import jinja2
@register.filter
@jinja2.contextfilter
def format_currencies(context, currencies):
cs = ', '.join(['%s %.2f' % (code, amount)
for code, amount in currencies.items()
if amount > 0.0])
if cs:
cs = '(%s)' % cs
return jinja2.Markup(cs)

Просмотреть файл

@ -0,0 +1,72 @@
{% extends 'acct_lookup/base.html' %}
{% block breadcrumbs %}
{% endblock %}
{% block content %}
<section class="island">
{{ _('Summary') }}
</section>
<section class="island c">
<h2>{{ account.email }} ({{ account.pk }})</h2>
<dl>
<dt>{{ _('Display Name') }}:</dt>
<dd>{{ account.display_name }}</dd>
<dt>{{ _('Username') }}:</dt>
<dd>{{ account.username }}</dd>
<dt>{{ _('Registered') }}:</dt>
<dd>{{ account.created|babel_datetime }}</dd>
<dt>UGC:</dt>
<dd>?</dd>
<dt>{{ _('Groups') }}:</dt>
<dd>
{% for group in account.groups.all() %}
<div>{{ group }}</div>
{% endfor %}
</dd>
</dl>
<h2>{{ _('Payments') }}</h2>
<dl>
<dt>{{ _('PayPal linked') }}:</dt>
<dd>TODO</dd>
<dt>{{ _('Marketplace Credit') }}:</dt>
<dd>TODO</dd>
<dt>{{ _('Payments') }}:</dt>
<dd>{{ _('apps purchased') }}: {{ app_summary['app_total'] }}
{{ app_summary['app_amount']|format_currencies }}</dd>
<dd>{{ _('in-app payments') }}: {{ app_summary['inapp_total'] }}
{{ app_summary['inapp_amount']|format_currencies }}</dd>
<dt>{{ _('Refunds') }}:</dt>
<dd>{{ refund_summary['requested'] }} {{ _('requested' ) }}</dd>
<dd>{{ refund_summary['approved'] }} {{ _('auto-approved') }}</dd>
</dl>
<h2>{{ _('Developer Program') }}</h2>
<dl>
<dt>{{ _('Read agreement') }}:</dt>
<dd>
{% if account.read_dev_agreement %}
{{ _('Yes') }}
{% else %}
{{ _('No') }}
{% endif %}
</dd>
<dt>{{ _('Address') }}:</dt>
<dd>TODO</dd>
<dt>{{ _('Submissions') }}:</dt>
<dd>
{% for addon in user_addons %}
<div><a href="{{ addon.get_detail_url() }}">
{% if addon.name %}
{{ addon.name }}
{% else %}
{{ _('Unnamed') }}
{% endif %}
</a>
({{ amo.ADDON_TYPE[addon.type] }})</div>
{% endfor %}
</dd>
</dl>
</section>
{% endblock %}

Просмотреть файл

@ -1,17 +1,102 @@
from decimal import Decimal
from nose.tools import eq_
from addons.models import Addon
import amo
from amo.urlresolvers import reverse
from amo.tests import TestCase
from amo.tests import TestCase, app_factory
from market.models import Refund
from stats.models import Contribution
from users.models import UserProfile
class TestViews(TestCase):
fixtures = ['base/users.json']
fixtures = ['base/users', 'webapps/337141-steamcube']
def setUp(self):
assert self.client.login(username='support-staff@mozilla.com',
password='password')
self.user_id = 31337 # steamcube
self.steamcube = Addon.objects.get(pk=337141)
self.otherapp = app_factory(app_slug='otherapp')
self.reg_user = UserProfile.objects.get(email='regular@mozilla.com')
self.summary_url = reverse('acct_lookup.summary', args=[self.user_id])
def test_authorization(self):
def buy_stuff(self, contrib_type):
for i in range(3):
if i == 1:
curr = 'GBR'
else:
curr = 'USD'
amount = Decimal('2.00')
Contribution.objects.create(addon=self.steamcube,
type=contrib_type,
currency=curr,
amount=amount,
user_id=self.user_id)
def summary(self, expected_status=200):
res = self.client.get(self.summary_url)
eq_(res.status_code, expected_status)
return res
def test_home_auth(self):
self.client.logout()
res = self.client.get(reverse('acct_lookup.home'))
self.assertLoginRedirects(res, reverse('acct_lookup.home'))
def test_summary_auth(self):
self.client.logout()
res = self.client.get(self.summary_url)
self.assertLoginRedirects(res, self.summary_url)
def test_home(self):
res = self.client.get(reverse('acct_lookup.home'))
self.assertNoFormErrors(res)
eq_(res.status_code, 200)
def test_basic_summary(self):
res = self.summary()
eq_(res.context['account'].pk, self.user_id)
def test_app_counts(self):
self.buy_stuff(amo.CONTRIB_PURCHASE)
sm = self.summary().context['app_summary']
eq_(sm['app_total'], 3)
eq_(sm['app_amount']['USD'], 4.0)
eq_(sm['app_amount']['GBR'], 2.0)
def test_inapp_counts(self):
self.buy_stuff(amo.CONTRIB_INAPP)
sm = self.summary().context['app_summary']
eq_(sm['inapp_total'], 3)
eq_(sm['inapp_amount']['USD'], 4.0)
eq_(sm['inapp_amount']['GBR'], 2.0)
def test_requested_refunds(self):
contrib = Contribution.objects.create(type=amo.CONTRIB_PURCHASE,
user_id=self.user_id,
addon=self.steamcube,
currency='USD',
amount='0.99')
Refund.objects.create(contribution=contrib)
res = self.summary()
eq_(res.context['refund_summary']['requested'], 1)
eq_(res.context['refund_summary']['approved'], 0)
def test_approved_refunds(self):
contrib = Contribution.objects.create(type=amo.CONTRIB_PURCHASE,
user_id=self.user_id,
addon=self.steamcube,
currency='USD',
amount='0.99')
Refund.objects.create(contribution=contrib,
status=amo.REFUND_APPROVED_INSTANT)
res = self.summary()
eq_(res.context['refund_summary']['requested'], 1)
eq_(res.context['refund_summary']['approved'], 1)
def test_app_created(self):
res = self.summary()
eq_(len(res.context['user_addons']), 1)

Просмотреть файл

@ -1,8 +1,15 @@
from django.conf.urls.defaults import patterns, url
from django.conf.urls.defaults import patterns, url, include
from . import views
urlpatterns = patterns('',
url('^$', views.home, name='acct_lookup.home'),
# These views all start with user ID.
detail_patterns = patterns('',
url(r'^summary$', views.summary, name='acct_lookup.summary'),
)
urlpatterns = patterns('',
url(r'^$', views.home, name='acct_lookup.home'),
(r'''^(?P<user_id>[^/<>"']+)/''', include(detail_patterns)),
)

Просмотреть файл

@ -1,9 +1,71 @@
from django.db import connection
from django.shortcuts import get_object_or_404
import jingo
import amo
from amo.decorators import login_required, permission_required
from market.models import Refund
from users.models import UserProfile
@login_required
@permission_required('AccountLookup', 'View')
def home(request):
return jingo.render(request, 'acct_lookup/home.html', {})
@login_required
@permission_required('AccountLookup', 'View')
def summary(request, user_id):
user = get_object_or_404(UserProfile, pk=user_id)
app_summary = _app_summary(user.pk)
# All refunds that this user has requested (probably as a consumer).
req = Refund.objects.filter(contribution__user=user)
# All instantly-approved refunds that this user has requested.
appr = req.filter(status=amo.REFUND_APPROVED_INSTANT)
refund_summary = {'approved': appr.count(),
'requested': req.count()}
user_addons = user.addons.all().order_by('-created')
return jingo.render(request, 'acct_lookup/summary.html',
{'account': user,
'app_summary': app_summary,
'refund_summary': refund_summary,
'user_addons': user_addons})
def _app_summary(user_id):
sql = """
select currency,
sum(case when type=%(purchase)s then 1 else 0 end)
as app_total,
sum(case when type=%(purchase)s then amount else 0.0 end)
as app_amount,
sum(case when type=%(inapp)s then 1 else 0 end)
as inapp_total,
sum(case when type=%(inapp)s then amount else 0.0 end)
as inapp_amount
from stats_contributions
where user_id=%(user_id)s
group by currency
"""
cursor = connection.cursor()
cursor.execute(sql, {'user_id': user_id,
'purchase': amo.CONTRIB_PURCHASE,
'inapp': amo.CONTRIB_INAPP})
summary = {'app_total': 0,
'app_amount': {},
'inapp_total': 0,
'inapp_amount': {}}
cols = [cd[0] for cd in cursor.description]
while 1:
row = cursor.fetchone()
if not row:
break
row = dict(zip(cols, row))
for cn in cols:
if cn.endswith('total'):
summary[cn] += row[cn]
elif cn.endswith('amount'):
summary[cn][row['currency']] = row[cn]
return summary