prettify refund page (bug 704961, bug 705871)

This commit is contained in:
Chris Van 2011-11-29 16:52:32 -08:00
Родитель 68d6c10475
Коммит a02cb78d3e
9 изменённых файлов: 134 добавлений и 110 удалений

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

@ -1,36 +1,49 @@
{% extends "devhub/base.html" %}
{% extends 'devhub/base_impala.html' %}
{% block title %}{{ dev_page_title(_('Issue Refund')) }}{% endblock %}
{% set title = _('Issue Refund') %}
{% block title %}{{ dev_page_title(title) }}{% endblock %}
{# TODO(apps): Finalize copy. #}
{% block content %}
<header>
<h1>{{ _('Issue Refund') }}</h1>
{{ dev_breadcrumbs(addon) }}
<h1>{{ title }}</h1>
</header>
<form method="post" id="issue-refund" class="item" action="">
{% if transaction_id %}
{{ csrf() }}
<p>
{% trans %}
A refund was requested by {{ user }} for {{ addon_name }}.
{% endtrans %}
</p><p>
{% trans %}
Price: {{ price }}
{% endtrans %}
</p><p>
{% trans %}
Purchase date: {{ purchase_date }}
{% endtrans %}
</p><p>
<button type="submit" name="issue">
{{ _('Issue Refund') }}
</button>
<button type="submit" name="decline">
{{ _('Decline Refund') }}
</button>
<input type="hidden" name="transaction_id" value="{{ transaction_id }}">
{% else %}
<p>{{ _('No refundable transaction found.') }}</p>
{% endif %}
<form method="post" action="" id="issue-refund" class="primary island full c">
{% if transaction_id %}
{{ csrf() }}
<p>
{% with user=contribution.user.display_name,
user_url=contribution.user.get_url_path(),
addon_url=addon.get_url_path(),
addon_name=addon.name %}
A refund was requested by
<a href="{{ user_url }}" target="_blank">{{ user }}</a> for
<a href="{{ addon_url }}" target="_blank">{{ addon_name }}</a>.
{% endwith %}
</p>
<p>
{% with price=contribution.get_amount_locale() %}
<b>Price:</b> {{ price }}
{% endwith %}
</p>
<p>
{% with purchase_date=contribution.created|datetime %}
<b>Purchase date:</b> {{ purchase_date }}
{% endwith %}
</p>
<p>
<button type="submit" class="good" name="issue">
{{ _('Issue Refund') }}
</button>
<button type="submit" class="bad" name="decline">
{{ _('Decline Refund') }}
</button>
<input type="hidden" name="transaction_id" value="{{ transaction_id }}">
</p>
{% else %}
<p>{{ loc('No refundable transaction found.') }}</p>
{% endif %}
</form>
{% endblock content %}
{% endblock %}

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

@ -1260,60 +1260,71 @@ class TestIssueRefund(amo.tests.TestCase):
self.paykey = u'fake-paykey'
self.client.login(username='del@icio.us', password='password')
self.user = UserProfile.objects.get(username='clouserw')
self.url = reverse('devhub.issue_refund', args=[self.addon.slug])
self.url = self.addon.get_dev_url('issue_refund')
def makePurchase(self, uuid='123456', type=amo.CONTRIB_PURCHASE):
def make_purchase(self, uuid='123456', type=amo.CONTRIB_PURCHASE):
return Contribution.objects.create(uuid=uuid, addon=self.addon,
transaction_id=self.transaction_id,
user=self.user, paykey=self.paykey,
amount=Decimal('10'), type=type)
def test_request_issue(self):
c = self.makePurchase()
r = self.client.get(self.url,
data={'transaction_id': c.transaction_id})
c = self.make_purchase()
r = self.client.get(self.url, {'transaction_id': c.transaction_id})
doc = pq(r.content)
eq_(doc('#issue-refund button')[0].text.strip(), 'Issue Refund')
eq_(doc('#issue-refund button')[1].text.strip(), 'Decline Refund')
eq_(doc('#issue-refund button').length, 2)
eq_(doc('#issue-refund input[name=transaction_id]').val(),
self.transaction_id)
def test_nonexistent_txn(self):
r = self.client.get(self.url, data={'transaction_id': 'none'})
r = self.client.get(self.url, {'transaction_id': 'none'})
eq_(r.status_code, 404)
def test_nonexistent_txn_no_really(self):
r = self.client.get(self.url)
eq_(r.status_code, 404)
@mock.patch('paypal.refund')
def test_issue(self, refund):
c = self.makePurchase()
r = self.client.post(self.url,
data={'transaction_id': c.transaction_id,
'issue': '1'})
eq_(r.status_code, 302)
def _test_issue(self, refund, destination):
c = self.make_purchase()
r = self.client.post(self.url, {'transaction_id': c.transaction_id,
'issue': '1'})
self.assertRedirects(r, reverse(destination), 302)
refund.assert_called_with(self.transaction_id, self.paykey)
eq_(len(mail.outbox), 1)
assert 'approved' in mail.outbox[0].subject
@mock.patch('paypal.refund')
def test_decline(self, refund):
c = self.makePurchase()
r = self.client.post(self.url,
data={'transaction_id': c.transaction_id,
'decline': ''})
eq_(r.status_code, 302)
def test_addons_issue(self, refund):
self._test_issue(refund, 'devhub.addons')
@mock.patch('paypal.refund')
def test_apps_issue(self, refund):
self.addon.update(type=amo.ADDON_WEBAPP)
self._test_issue(refund, 'devhub.apps')
def _test_decline(self, refund, destination):
c = self.make_purchase()
r = self.client.post(self.url, {'transaction_id': c.transaction_id,
'decline': ''})
self.assertRedirects(r, reverse(destination), 302)
assert not refund.called
eq_(len(mail.outbox), 1)
assert 'declined' in mail.outbox[0].subject
@mock.patch('paypal.refund')
def test_addons_decline(self, refund):
self._test_decline(refund, 'devhub.addons')
@mock.patch('paypal.refund')
def test_apps_decline(self, refund):
self.addon.update(type=amo.ADDON_WEBAPP)
self._test_decline(refund, 'devhub.apps')
@mock.patch('paypal.refund')
def test_non_refundable_txn(self, refund):
c = self.makePurchase('56789', amo.CONTRIB_VOLUNTARY)
r = self.client.post(self.url,
data={'transaction_id': c.transaction_id,
'issue': ''})
c = self.make_purchase('56789', amo.CONTRIB_VOLUNTARY)
r = self.client.post(self.url, {'transaction_id': c.transaction_id,
'issue': ''})
eq_(r.status_code, 404)
assert not refund.called

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

@ -61,6 +61,7 @@ app_detail_patterns = patterns('',
url('^profile$', views.profile, name='devhub.apps.profile'),
url('^profile/remove$', views.remove_profile,
name='devhub.apps.profile.remove'),
url('^issue_refund$', views.issue_refund, name='devhub.apps.issue_refund'),
)
# These will all start with /addon/<addon_id>/
@ -81,7 +82,8 @@ detail_patterns = patterns('',
url('^payments/permission/refund$', views.acquire_refund_permission,
name='devhub.addons.acquire_refund_permission'),
url('^payments/', include(marketplace_patterns('addons'))),
url('^issue_refund$', views.issue_refund, name='devhub.issue_refund'),
url('^issue_refund$', views.issue_refund,
name='devhub.addons.issue_refund'),
url('^profile$', views.profile, name='devhub.addons.profile'),
url('^profile/remove$', views.remove_profile,
name='devhub.addons.profile.remove'),

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

@ -492,23 +492,19 @@ def issue_refund(request, addon_id, addon, webapp=False):
if 'issue' in request.POST:
paypal.refund(txn_id, contribution.paykey)
contribution.mail_approved()
paypal_log.error('Refund issued for transaction %r' % (txn_id,))
paypal_log.error('Refund issued for transaction %r' % txn_id)
messages.success(request, 'Refund issued.')
return redirect('devhub.addons')
else:
contribution.mail_declined()
paypal_log.error('Refund declined for transaction %r' % (txn_id,))
paypal_log.error('Refund declined for transaction %r' % txn_id)
messages.success(request, 'Refund declined.')
return redirect('devhub.addons')
return redirect('devhub.%s' % ('apps' if webapp else 'addons'))
else:
return jingo.render(request, 'devhub/payments/issue-refund.html',
{'refund_issued': False,
'user': contribution.user.display_name,
'addon_name': addon.name,
{'contribution': contribution,
'addon': addon,
'webapp': webapp,
'price': contribution.amount,
'transaction_id': txn_id,
'purchase_date': contribution.created})
'transaction_id': txn_id})
@dev_required
@ -1028,7 +1024,6 @@ def addons_section(request, addon_id, addon, section, editable=False,
else:
form = False
#import pdb; pdb.set_trace()
data = {'addon': addon,
'webapp': webapp,
'form': form,

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

@ -467,7 +467,6 @@ def profile(request, user_id):
.filter(following__user=user)
.order_by('-following__created'))[:10]
edit_any_user = acl.action_allowed(request, 'Admin', 'EditAnyUser')
own_profile = (request.user.is_authenticated() and
request.amo_user.id == user.id)
@ -760,11 +759,8 @@ def support_mozilla(request, contribution, wizard):
def refund_request(request, contribution, wizard):
addon = contribution.addon
form = forms.RemoveForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
return redirect(reverse('users.support',
args=[contribution.pk, 'reason']))
if request.method == 'POST' and form.is_valid():
return redirect('users.support', contribution.pk, 'reason')
return wizard.render(request, wizard.tpl('request.html'),
{'addon': addon, 'webapp': addon.is_webapp(),
'form': form, 'contribution': contribution})
@ -773,35 +769,30 @@ def refund_request(request, contribution, wizard):
def refund_reason(request, contribution, wizard):
addon = contribution.addon
if not 'request' in wizard.get_progress():
return redirect(reverse('users.support',
args=[contribution.pk, 'request']))
return redirect('users.support', contribution.pk, 'request')
form = forms.ContactForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
# if under 30 minutes, refund
# TODO(ashort): add in the logic for under 30 minutes
refund_url = absolutify(urlparams(
reverse('devhub.issue_refund', args=[addon.slug]),
transaction_id=contribution.transaction_id))
if request.method == 'POST' and form.is_valid():
# TODO(ashort): Reject refund if purchase was more than 30 minutes ago.
url = absolutify(urlparams(addon.get_dev_url('issue_refund'),
transaction_id=contribution.transaction_id))
template = jingo.render_to_string(request,
wizard.tpl('emails/refund-request.txt'),
context={'addon': addon,
'form': form,
'user': request.amo_user,
'contribution': contribution,
'refund_url': url})
log.info('Refund request sent by user: %s for addon: %s' %
(request.amo_user.pk, addon.pk))
# L10n: %s is the addon name.
send_mail(_(u'New Refund Request for %s' % addon.name),
template, request.amo_user.email,
[smart_str(addon.support_email)])
return redirect(reverse('users.support',
args=[contribution.pk, 'refund-sent']))
template = jingo.render_to_string(request,
wizard.tpl('emails/refund-request.txt'),
context={'addon': addon, 'form': form,
'user': request.amo_user,
'contribution': contribution,
'refund_url': refund_url})
log.info('Refund request sent by user: %s for addon: %s' %
(request.amo_user.pk, addon.pk))
# L10n: %s is the addon name.
send_mail(_(u'New Refund Request for %s' % addon.name),
template, request.amo_user.email,
[smart_str(addon.support_email)])
return redirect(reverse('users.support',
args=[contribution.pk, 'refund-sent']))
return wizard.render(request, wizard.tpl('refund.html'),
{'contribut': addon, 'form': form})
return wizard.render(request, wizard.tpl('refund.html'), {'form': form})
class SupportWizard(Wizard):

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

@ -1,4 +1,4 @@
@import 'lib';
@import '../impala/lib';
.devhub-form .tip,
.addon-submission-process .tip,
@ -92,3 +92,7 @@ a.remove:hover {
.html-rtl .undo {
float: left;
}
#issue-refund {
font-size: 14px;
}

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

@ -15,6 +15,17 @@
.box-shadow(0 1px rgba(0, 0, 0, 0.1), 0 -2px rgba(0, 0, 0, 0.1) inset);
border: 0;
}
button.good, .button.add { // Green
background: #489615;
.gradient-two-color(#84C63C, #489615);
}
button.bad, .button.developer, .button.scary { // Red
background: #bc2b1a;
.gradient-two-color(#f84b4e, #bc2b1a);
}
.button {
display: inline-block;
&.prominent {
@ -23,9 +34,6 @@
.box-shadow(0 3px rgba(0, 0, 0, 0.1), 0 -4px rgba(0, 0, 0, 0.1) inset);
}
&.add { // Green
background: #489615;
.gradient-two-color(#84C63C, #489615);
color: #fff;
span {
padding-left: 16px;
background: url(../../img/impala/button-icons.png) no-repeat 0 3px;
@ -93,9 +101,6 @@
}
}
&.developer, &.scary { // Red
background: #bc2b1a;
.gradient-two-color(#f84b4e, #bc2b1a);
color: #fff;
span {
margin-left: -4px;
padding-left: 24px;
@ -106,7 +111,6 @@
&.watch:not(.watching) { // Orange
background: #ea0;
.gradient-two-color(#ea0, darken(#ea0, 10%));
color: #fff;
}
&.platform {
display: none;

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

@ -32,6 +32,11 @@ p.req {
margin: 0 0 1em;
}
/* CSRF token */
form div[style]:first-child + p {
margin-top: 0;
}
.optional {
color: @note-gray;
font-size: 11px;
@ -380,4 +385,3 @@ button.loading-submit:after {
top: 0;
width: 16px;
}

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

@ -506,7 +506,7 @@ MINIFY_BUNDLES = {
'css/impala/devhub-popups.less',
'css/impala/devhub-compat.less',
'css/impala/formset.less',
'css/impala/devhub-forms.less',
'css/devhub/forms.less',
),
'zamboni/devhub_impala': (
'css/impala/developers.less',
@ -514,7 +514,7 @@ MINIFY_BUNDLES = {
'css/impala/devhub-popups.less',
'css/impala/devhub-compat.less',
'css/impala/devhub-dashboard.less',
'css/impala/devhub-forms.less',
'css/devhub/forms.less',
),
'zamboni/editors': (
'css/zamboni/editors.css',