Skip to content
This repository was archived by the owner on Mar 15, 2018. It is now read-only.

Commit b9335c7

Browse files
author
Andy McKay
committed
always show support for inapp and ensure already refunded transactions cant be refunded (bug 747174)
1 parent 35b9986 commit b9335c7

File tree

7 files changed

+58
-2
lines changed

7 files changed

+58
-2
lines changed

apps/stats/models.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,17 @@ def is_instant_refund(self):
364364
limit = datetime.timedelta(seconds=settings.PAYPAL_REFUND_INSTANT)
365365
return datetime.datetime.now() < (self.created + limit)
366366

367+
def is_refunded(self):
368+
"""
369+
If related has been set, then this transaction has been refunded or
370+
charged back. This is a bit expensive, so refrain from using on listing
371+
pages.
372+
"""
373+
return (Contribution.objects.filter(related=self,
374+
type__in=[amo.CONTRIB_REFUND,
375+
amo.CONTRIB_CHARGEBACK])
376+
.exists())
377+
367378

368379
models.signals.post_save.connect(Contribution.post_save, sender=Contribution)
369380

apps/stats/tests/test_models.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@ def test_not_instant_refund(self):
6464
self.con.update(created=datetime.now() - diff)
6565
assert not self.con.is_instant_refund(), "Refund shouldn't be instant"
6666

67+
def test_refunded(self):
68+
user = UserProfile.objects.create(username='foo@bar.com')
69+
addon = Addon.objects.create(type=amo.ADDON_EXTENSION)
70+
71+
assert not self.con.is_refunded()
72+
Contribution.objects.create(user=user, addon=addon, related=self.con,
73+
type=amo.CONTRIB_REFUND)
74+
assert self.con.is_refunded()
6775

6876
def test_refund_inapp_instant(self):
6977
for ctype in ('CONTRIB_INAPP', 'CONTRIB_INAPP_PENDING'):

mkt/account/templates/account/helpers/refund_info.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
{% endtrans %}
2323
{% endif %}
2424
</span>
25-
{% if get_support %}
25+
{% if get_support or contribution.type == amo.CONTRIB_INAPP %}
2626
<a class="request-support"
2727
href="{{ url('support', contribution.pk) }}">
2828
{{ _('Request Support') }}</a>

mkt/account/tests/test_views.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,9 @@ def get_support_url(self, *args):
522522

523523
class TestPurchases(PurchaseBase):
524524

525+
def get_support_url(self, pk=None, *args):
526+
return reverse('support', args=[pk or self.con.pk] + list(args))
527+
525528
def make_contribution(self, product, amt, type, day, user=None):
526529
c = Contribution.objects.create(user=user or self.user,
527530
addon=product, amount=amt, type=type)
@@ -629,6 +632,15 @@ def test_support_link_inapp(self):
629632
eq_(self.get_pq()('a.request-support').eq(0).attr('href'),
630633
self.get_support_url())
631634

635+
def test_support_link_inapp_multiple(self):
636+
self.con.update(type=amo.CONTRIB_INAPP)
637+
con = self.make_contribution(self.con.addon, 1, amo.CONTRIB_INAPP, 2)
638+
res = self.get_pq()
639+
eq_(res('a.request-support').eq(0).attr('href'),
640+
self.get_support_url())
641+
eq_(res('a.request-support').eq(1).attr('href'),
642+
self.get_support_url(pk=con.pk))
643+
632644
def test_support_text_inapp(self):
633645
self.con.update(type=amo.CONTRIB_INAPP)
634646
assert self.get_pq()('span.purchase').eq(0).text().startswith('In-app')

mkt/support/templates/support/start.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ <h1>{{ _('What do you need help with?') }}</h1>
77
{{ _("I can't install my purchase") }} &raquo;</a></li>
88
<li><a href="{{ url('support', contribution.pk, 'resources') }}">
99
{{ _('I have billing or payment concerns') }} &raquo;</a></li>
10-
{% if waffle.switch('allow-refund') %}
10+
{% if waffle.switch('allow-refund') and not contribution.is_refunded() %}
1111
<li><a href="{{ url('support', contribution.pk, 'request') }}">
1212
{{ _('I want to request a refund') }} &raquo;</a></li>
1313
{% else %}

mkt/support/tests/test_views.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ def test_support_page_form(self):
3131
eq_(doc('#support-start').find('a').eq(0).attr('href'),
3232
self.get_support_url('author'))
3333

34+
def test_refund_link(self):
35+
doc = pq(self.client.get(self.get_support_url()).content)
36+
eq_(len(doc('#support-start').find('a')), 4)
37+
38+
@mock.patch('apps.stats.models.Contribution.is_refunded')
39+
def test_no_refund_link(self, is_refunded):
40+
is_refunded.return_value = True
41+
doc = pq(self.client.get(self.get_support_url()).content)
42+
eq_(len(doc('#support-start').find('a')), 3)
43+
3444
def test_support_page_external_link(self):
3545
self.app.support_url = 'http://omg.org/yes'
3646
self.app.save()
@@ -122,6 +132,16 @@ def test_no_txnid_request(self):
122132
eq_(len(mail.outbox), 0)
123133
self.assertRedirects(res, reverse('account.purchases'), 302)
124134

135+
@mock.patch('apps.stats.models.Contribution.is_refunded')
136+
def test_already_refunded_request(self, is_refunded):
137+
is_refunded.return_value = True
138+
self.client.post(self.get_support_url('request'), {'remove': 1})
139+
res = self.client.post(self.get_support_url('reason'),
140+
{'text': 'something'})
141+
assert 'refunded' in res.cookies['messages'].value
142+
eq_(len(mail.outbox), 0)
143+
self.assertRedirects(res, reverse('account.purchases'), 302)
144+
125145
@mock.patch('stats.models.Contribution.is_instant_refund')
126146
def test_request_mails(self, is_instant_refund):
127147
is_instant_refund.return_value = False

mkt/support/views.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,11 @@ def refund_reason(request, contribution, wizard):
119119
'transaction_id: %r' % contribution.pk)
120120
return redirect('account.purchases')
121121

122+
if contribution.is_refunded():
123+
messages.error(request, _('This has already been refunded.'))
124+
paypal_log.info('Already refunded: %s' % contribution.pk)
125+
return redirect('account.purchases')
126+
122127
if contribution.is_instant_refund():
123128
try:
124129
paypal.refund(contribution.paykey)

0 commit comments

Comments
 (0)