allow refunds, just not instant ones for in-app (bug 746417)

This commit is contained in:
Andy McKay 2012-04-18 07:37:34 -07:00
Родитель d0b25d4021
Коммит 9509f4bebe
6 изменённых файлов: 24 добавлений и 49 удалений

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

@ -340,15 +340,8 @@ class Contribution(amo.models.ModelBase):
def get_absolute_refund_url(self): def get_absolute_refund_url(self):
return absolutify(self.get_refund_url()) return absolutify(self.get_refund_url())
def can_we_refund(self):
"""
We can only refund a purchase.
We cannot refund in-app payments; PayPal can however.
"""
return self.type == amo.CONTRIB_PURCHASE
def is_instant_refund(self): def is_instant_refund(self):
if not self.can_we_refund(): if self.type != amo.CONTRIB_PURCHASE:
return False return False
limit = datetime.timedelta(seconds=settings.PAYPAL_REFUND_INSTANT) limit = datetime.timedelta(seconds=settings.PAYPAL_REFUND_INSTANT)
return datetime.datetime.now() < (self.created + limit) return datetime.datetime.now() < (self.created + limit)

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

@ -57,20 +57,17 @@ class TestContributionModel(amo.tests.TestCase):
def test_instant_refund(self): def test_instant_refund(self):
self.con.update(created=datetime.now()) self.con.update(created=datetime.now())
assert self.con.can_we_refund(), 'Refund on purchases'
assert self.con.is_instant_refund(), 'Refund should be instant' assert self.con.is_instant_refund(), 'Refund should be instant'
def test_not_instant_refund(self): def test_not_instant_refund(self):
diff = timedelta(seconds=settings.PAYPAL_REFUND_INSTANT + 10) diff = timedelta(seconds=settings.PAYPAL_REFUND_INSTANT + 10)
self.con.update(created=datetime.now() - diff) self.con.update(created=datetime.now() - diff)
assert self.con.can_we_refund(), 'Refund on purchases'
assert not self.con.is_instant_refund(), "Refund shouldn't be instant" assert not self.con.is_instant_refund(), "Refund shouldn't be instant"
def test_refund_inapp_instant(self): def test_refund_inapp_instant(self):
for ctype in ('CONTRIB_INAPP', 'CONTRIB_INAPP_PENDING'): for ctype in ('CONTRIB_INAPP', 'CONTRIB_INAPP_PENDING'):
self.con.update(created=datetime.now(), type=getattr(amo, ctype)) self.con.update(created=datetime.now(), type=getattr(amo, ctype))
assert not self.con.can_we_refund(), (
'No refund on %s inapp' % ctype)
assert not self.con.is_instant_refund(), ( assert not self.con.is_instant_refund(), (
'No refund on %s inapp' % ctype) 'No refund on %s inapp' % ctype)
@ -79,12 +76,9 @@ class TestContributionModel(amo.tests.TestCase):
for ctype in ('CONTRIB_INAPP', 'CONTRIB_INAPP_PENDING'): for ctype in ('CONTRIB_INAPP', 'CONTRIB_INAPP_PENDING'):
self.con.update(created=datetime.now() - diff, self.con.update(created=datetime.now() - diff,
type=getattr(amo, ctype)) type=getattr(amo, ctype))
assert not self.con.can_we_refund(), (
'No refund on %s inapp' % ctype)
assert not self.con.is_instant_refund(), ( assert not self.con.is_instant_refund(), (
'No refund on %s inapp' % ctype) 'No refund on %s inapp' % ctype)
class TestEmail(amo.tests.TestCase): class TestEmail(amo.tests.TestCase):
fixtures = ['base/users', 'base/addon_3615'] fixtures = ['base/users', 'base/addon_3615']

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

@ -2,14 +2,24 @@
<form method="post"> <form method="post">
{{ csrf() }} {{ csrf() }}
<p> <p>
{% trans support_url=url('support', contribution.pk, 'author') %} {% if contribution.type == amo.CONTRIB_INAPP %}
If you are unsatisfied with your purchase, you may request a {% trans support_url=url('support', contribution.pk, 'author') %}
refund from the developer for up to 60 days. Requests within 30 If you are unsatisfied with your purchase, you may request a
minutes after purchase are automatically granted. If you are refund from the developer for up to 60 days. If you are
having difficulty using the app, we encourage you to having difficulty using the app, we encourage you to
<a href="{{ support_url }}">ask the developer for support</a> before <a href="{{ support_url }}">ask the developer for support</a> before
requesting a refund. requesting a refund.
{% endtrans %} {% endtrans %}
{% else %}
{% trans support_url=url('support', contribution.pk, 'author') %}
If you are unsatisfied with your purchase, you may request a
refund from the developer for up to 60 days. Requests within 30
minutes after purchase are automatically granted. If you are
having difficulty using the app, we encourage you to
<a href="{{ support_url }}">ask the developer for support</a> before
requesting a refund.
{% endtrans %}
{% endif %}
</p> </p>
<p class="form-footer"> <p class="form-footer">
<button type="submit">{{ _('Continue') }}</button> {{ _('or') }} <button type="submit">{{ _('Continue') }}</button> {{ _('or') }}

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

@ -8,12 +8,8 @@
<li><a href="{{ url('support', contribution.pk, 'resources') }}"> <li><a href="{{ url('support', contribution.pk, 'resources') }}">
{{ _('I have billing or payment concerns') }} &raquo;</a></li> {{ _('I have billing or payment concerns') }} &raquo;</a></li>
{% if waffle.switch('allow-refund') %} {% if waffle.switch('allow-refund') %}
{% if contribution.can_we_refund() %} <li><a href="{{ url('support', contribution.pk, 'request') }}">
<li><a href="{{ url('support', contribution.pk, 'request') }}"> {{ _('I want to request a refund') }} &raquo;</a></li>
{{ _('I want to request a refund') }} &raquo;</a></li>
{% elif contribution.type == amo.CONTRIB_INAPP %}
<li>{{ _('In-app purchases cannot be refunded through the Marketplace.') }}</li>
{% endif %}
{% else %} {% else %}
{# No L10n or even `loc` on purpose. #} {# No L10n or even `loc` on purpose. #}
<li> <li>

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

@ -31,13 +31,6 @@ class TestRequestSupport(PurchaseBase):
eq_(doc('#support-start').find('a').eq(0).attr('href'), eq_(doc('#support-start').find('a').eq(0).attr('href'),
self.get_support_url('author')) self.get_support_url('author'))
def test_start_no_inapp_refund(self):
self.con.update(type=amo.CONTRIB_INAPP)
r = self.client.get(self.get_support_url())
content = r.content.decode('utf-8')
eq_(pq(content)('#support-start').find('a').length, 3)
assert self.get_support_url('request') not in content
def test_support_page_external_link(self): def test_support_page_external_link(self):
self.app.support_url = 'http://omg.org/yes' self.app.support_url = 'http://omg.org/yes'
self.app.save() self.app.save()
@ -94,10 +87,10 @@ class TestRequestSupport(PurchaseBase):
res = self.client.post(self.get_support_url('mozilla'), {'b': 'c'}) res = self.client.post(self.get_support_url('mozilla'), {'b': 'c'})
assert 'text' in res.context['form'].errors assert 'text' in res.context['form'].errors
def test_no_request_inapp(self): def test_request_inapp(self):
self.con.update(type=amo.CONTRIB_INAPP) self.con.update(type=amo.CONTRIB_INAPP)
res = self.client.post(self.get_support_url('request')) res = self.client.post(self.get_support_url('request'))
eq_(res.status_code, 403) eq_(res.status_code, 302)
def test_refund_remove(self): def test_refund_remove(self):
res = self.client.post(self.get_support_url('request'), {'remove': 1}) res = self.client.post(self.get_support_url('request'), {'remove': 1})
@ -127,11 +120,6 @@ class TestRequestSupport(PurchaseBase):
eq_(len(mail.outbox), 0) eq_(len(mail.outbox), 0)
self.assertRedirects(res, reverse('account.purchases'), 302) self.assertRedirects(res, reverse('account.purchases'), 302)
def test_no_reason_inapp(self):
self.con.update(type=amo.CONTRIB_INAPP)
res = self.client.post(self.get_support_url('reason'))
eq_(res.status_code, 403)
@mock.patch('stats.models.Contribution.is_instant_refund') @mock.patch('stats.models.Contribution.is_instant_refund')
def test_request_mails(self, is_instant_refund): def test_request_mails(self, is_instant_refund):
is_instant_refund.return_value = False is_instant_refund.return_value = False

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

@ -99,9 +99,6 @@ def support_mozilla(request, contribution, wizard):
@waffle_switch('allow-refund') @waffle_switch('allow-refund')
def refund_request(request, contribution, wizard): def refund_request(request, contribution, wizard):
if not contribution.can_we_refund():
return http.HttpResponseForbidden()
addon = contribution.addon addon = contribution.addon
if request.method == 'POST': if request.method == 'POST':
return redirect('support', contribution.pk, 'reason') return redirect('support', contribution.pk, 'reason')
@ -112,9 +109,6 @@ def refund_request(request, contribution, wizard):
@waffle_switch('allow-refund') @waffle_switch('allow-refund')
def refund_reason(request, contribution, wizard): def refund_reason(request, contribution, wizard):
if not contribution.can_we_refund():
return http.HttpResponseForbidden()
addon = contribution.addon addon = contribution.addon
if not 'request' in wizard.get_progress(): if not 'request' in wizard.get_progress():
return redirect('support', contribution.pk, 'request') return redirect('support', contribution.pk, 'request')