Merge pull request #808 from muffinresearch/price-tiers-ui-868179
Price tiers UI (bug 868179)
This commit is contained in:
Коммит
6f8b459c34
|
@ -62,7 +62,7 @@ class Price(amo.models.ModelBase):
|
|||
return _('Tier %s' % self.name)
|
||||
|
||||
def __unicode__(self):
|
||||
return u'%s - $%s' % (self.tier_name(), self.price)
|
||||
return u'$%s' % self.price
|
||||
|
||||
@staticmethod
|
||||
def transformer(prices):
|
||||
|
|
|
@ -457,6 +457,24 @@ button.loading-submit:after,
|
|||
table td {
|
||||
border-top: 0;
|
||||
}
|
||||
.regions table {
|
||||
tr:last-child th,
|
||||
th {
|
||||
border-top: 0;
|
||||
font-size: 12px;
|
||||
padding: 1em 0;
|
||||
}
|
||||
td {
|
||||
border-top: 1px dotted $border-taupe;
|
||||
vertical-align: middle;
|
||||
}
|
||||
tr:first-child th {
|
||||
padding: 0 0 1em;
|
||||
}
|
||||
tr:first-child td {
|
||||
padding: 1em 0;
|
||||
}
|
||||
}
|
||||
.screenshot.thumbnail {
|
||||
width: 100px;
|
||||
height: 75px;
|
||||
|
|
|
@ -333,12 +333,12 @@ form .char-count b {
|
|||
padding-top: 0;
|
||||
}
|
||||
|
||||
.checkbox-choices {
|
||||
.checkbox-choices:not(.regions) {
|
||||
columns(3, 1.5em);
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
|
||||
td .checkbox-choices {
|
||||
td .checkbox-choices:not(.regions) {
|
||||
column-count(2);
|
||||
}
|
||||
|
||||
|
|
|
@ -420,3 +420,30 @@
|
|||
.rejected .modify-account {
|
||||
display: none;
|
||||
}
|
||||
|
||||
label.disabled {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.devhub-form table td.region-container {
|
||||
border: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.devhub-form table th.region-toggle {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.regions {
|
||||
.region-heading {
|
||||
display: block;
|
||||
hidetext();
|
||||
}
|
||||
.local-currency-heading,
|
||||
.my-currency {
|
||||
display: block;
|
||||
}
|
||||
td .local-retail {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
var $this = $(this);
|
||||
var $choices = $this.closest('td, div').find('.checkbox-choices input[type=checkbox]:not(:disabled)');
|
||||
if ($this.hasClass('all')) {
|
||||
$choices.attr('checked', true);
|
||||
$choices.prop('checked', true).trigger('change');
|
||||
} else {
|
||||
$choices.removeAttr('checked');
|
||||
$choices.prop('checked', false).trigger('change');
|
||||
}
|
||||
})).on('editLoaded.disableCheckboxes', function(e) {
|
||||
// Disable individual checkbox fields when we see them.
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
define('payments', [], function() {
|
||||
'use strict';
|
||||
|
||||
var currentPrice;
|
||||
var $regions = $('.regions');
|
||||
var pricesApiEndpoint = $regions.data('pricelistApiUrl') + '{0}/';
|
||||
|
||||
function getOverlay(opts) {
|
||||
var id = opts;
|
||||
if (_.isObject(opts)) {
|
||||
|
@ -18,7 +22,7 @@ define('payments', [], function() {
|
|||
}
|
||||
|
||||
function setupPaymentAccountOverlay($overlay, onsubmit) {
|
||||
$overlay.on('submit', 'form', _pd(function(e) {
|
||||
$overlay.on('submit', 'form', _pd(function() {
|
||||
var $form = $(this);
|
||||
var $waiting_overlay = getOverlay('bango-waiting');
|
||||
var $old_overlay = $overlay.children('section');
|
||||
|
@ -68,18 +72,80 @@ define('payments', [], function() {
|
|||
}));
|
||||
}
|
||||
|
||||
function updatePrices() {
|
||||
/*jshint validthis:true */
|
||||
var $this = $(this);
|
||||
var selectedPrice = $this.val() || '';
|
||||
var apiUrl = format(pricesApiEndpoint, parseInt(selectedPrice, 10));
|
||||
var disabledRegions = $regions.data('disabledRegions');
|
||||
|
||||
if (currentPrice == selectedPrice) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear out existing price data.
|
||||
$regions.find('.local-retail').text('');
|
||||
|
||||
$.ajax({
|
||||
url: apiUrl,
|
||||
success: function(data) {
|
||||
var prices = data.prices || [];
|
||||
var tierPrice = data.price;
|
||||
var seen = [];
|
||||
// Iterate over the prices for the regions
|
||||
for (var i=0, j=prices.length; i<j; i++) {
|
||||
var price = prices[i];
|
||||
var region = price.region;
|
||||
var $chkbox = $regions.find('input:checkbox[value=' + region + ']');
|
||||
// Skip if over regions that should be disabled e.g games app in Brazil.
|
||||
if (disabledRegions.indexOf(region) > -1) {
|
||||
continue;
|
||||
}
|
||||
// Enable checkboxes for those that we have price info for.
|
||||
$chkbox.prop('disabled', false)
|
||||
.parent('label').removeClass('disabled')
|
||||
.closest('tr').find('.local-retail')
|
||||
.text(price.price +' '+ price.currency)
|
||||
.toggle($chkbox.prop('checked'));
|
||||
seen.push($chkbox[0]);
|
||||
}
|
||||
// Disable everything else.
|
||||
$regions.find('input[type=checkbox]').not(seen)
|
||||
.prop('checked', false)
|
||||
.prop('disabled', true)
|
||||
.parent('label').addClass('disabled')
|
||||
.trigger('change');
|
||||
},
|
||||
dataType: "json"
|
||||
});
|
||||
|
||||
currentPrice = selectedPrice;
|
||||
}
|
||||
|
||||
function handleCheckboxChange() {
|
||||
/*jshint validthis:true */
|
||||
var $this = $(this);
|
||||
$this.closest('tr').find('.local-retail').toggle($this.prop('checked'));
|
||||
}
|
||||
|
||||
function init() {
|
||||
$('#regions').trigger('editLoaded');
|
||||
|
||||
$('.update-payment-type button').click(function(e) {
|
||||
$('.update-payment-type button').click(function() {
|
||||
$('input[name=toggle-paid]').val($(this).data('type'));
|
||||
});
|
||||
|
||||
var $paid_island = $('#paid-island, #paid-upsell-island');
|
||||
var $paid_island = $('#paid-island, #paid-upsell-island, #paid-regions-island');
|
||||
var $free_island = $('#regions-island');
|
||||
$('#submit-payment-type.hasappendix').on('tabs-changed', function(e, tab) {
|
||||
$paid_island.toggle(tab.id == 'paid-tab-header');
|
||||
$free_island.toggle(tab.id == 'free-tab-header');
|
||||
});
|
||||
|
||||
$('#id_price').on('change', updatePrices)
|
||||
.each(updatePrices);
|
||||
|
||||
$('.regions').on('change', 'input[type=checkbox]', handleCheckboxChange);
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
<p class="note disabled-regions">
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Apps/Marketplace_Review" target="_blank">
|
||||
{{ _('Learn why some regions are restricted.') }}</a>
|
||||
</p>
|
|
@ -0,0 +1,7 @@
|
|||
<div class="island warning">
|
||||
{% trans %}
|
||||
Your app will no longer be listed in certain regions because those
|
||||
regions do not support payments. We have transferred your region
|
||||
choices. Please review the changes before saving.
|
||||
{% endtrans %}
|
||||
</div>
|
|
@ -0,0 +1,11 @@
|
|||
{{ region_form.other_regions }}
|
||||
{{ region_form.other_regions.label_tag() }}
|
||||
{{ region_form.other_regions.errors }}
|
||||
<div class="hint note">
|
||||
{%- trans %}
|
||||
Your app will be displayed in the worldwide Marketplace and
|
||||
in any regional marketplace that is added in the future.
|
||||
You will receive an email notification when a new region
|
||||
is added.
|
||||
{% endtrans -%}
|
||||
</div>
|
|
@ -0,0 +1,6 @@
|
|||
<label data-for="region">{{ region_form.regions.label }}</label>
|
||||
{{ region_form.non_field_errors() }}
|
||||
<p class="toggles">
|
||||
<a href="#" class="all">{{ _('Select All') }}</a> ·
|
||||
<a href="#" class="none">{{ _('None') }}</a>
|
||||
</p>
|
|
@ -105,7 +105,7 @@
|
|||
{% if is_paid %}
|
||||
<div id="paid-island">
|
||||
{{ disabled_payments_notice() }}
|
||||
<h2>{{ _('Prices and payment accounts') }}</h2>
|
||||
<h2>{{ _('Payment accounts') }}</h2>
|
||||
{% if is_incomplete %}
|
||||
<div class="island warning">
|
||||
{%- trans %}
|
||||
|
@ -115,6 +115,38 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
<section class="island payments">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th><label data-for="accounts">{{ _('Payment Account') }}</label></th>
|
||||
<td>
|
||||
<div id="bango-account-list" data-url="{{ url('mkt.developers.bango.payment_accounts_form') }}">
|
||||
{{ bango_account_list_form.errors }}
|
||||
{% include 'developers/payments/includes/bango_accounts_form.html' %}
|
||||
</div>
|
||||
<a href="#" class="payment-account-actions" data-action="add">
|
||||
{{- _('Add or manage payment accounts') -}}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="listing-footer">
|
||||
<button>{{ _('Save Changes') }}</button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if is_paid %}
|
||||
<div id="paid-regions-island">
|
||||
<h2>{{ _('Prices and countries') }}</h2>
|
||||
|
||||
{% if region_form.has_inappropriate_regions() %}
|
||||
{% include 'developers/payments/includes/regions_inappropriate.html' %}
|
||||
{% endif %}
|
||||
|
||||
<section id="regions" class="island">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
|
@ -134,6 +166,91 @@
|
|||
{{ form.allow_inapp }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="2" class="region-toggle">
|
||||
{% include 'developers/payments/includes/regions_toggle.html' %}
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="region-container">
|
||||
<div class="checkbox-choices regions"
|
||||
data-disabled-regions="{{ region_form.disabled_regions|json }}"
|
||||
data-pricelist-api-url="{{ api_pricelist_url }}">
|
||||
{{ region_form.regions.errors }}
|
||||
<table>
|
||||
<thead>
|
||||
<th><span class="region-heading">{{ _('Region') }}</span></th>
|
||||
<th>{{ _('Retail price') }}
|
||||
<span class="local-currency-heading">({{ _('local currency') }})</span></th>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for value, text in region_form.regions.field.choices %}
|
||||
<tr>
|
||||
<td>
|
||||
<label class="disabled">
|
||||
<input type="checkbox" disabled
|
||||
{% if value in region_form.initial.regions %}checked{% endif %}
|
||||
name="regions" value="{{ value }}" />{{ text }}</label>
|
||||
</td>
|
||||
<td><span class="local-retail"></span></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% if region_form.disabled_regions %}
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
{% include 'developers/payments/includes/regions_disabled.html' %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
{% include 'developers/payments/includes/regions_other.html' %}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="listing-footer">
|
||||
<button class="button">{{ _('Save Changes') }}</button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
{% else %}
|
||||
{# Non-paid app region lists #}
|
||||
<div id="regions-island">
|
||||
<h2>{{ _('Regions and listings') }}</h2>
|
||||
{% if region_form.has_inappropriate_regions() %}
|
||||
{% include 'developers/payments/includes/regions_inappropriate.html' %}
|
||||
{% endif %}
|
||||
<section id="regions" class="island">
|
||||
{% include 'developers/payments/includes/regions_toggle.html' %}
|
||||
{{ region_form.regions.errors }}
|
||||
<div class="checkbox-choices"
|
||||
data-disabled="{{ region_form.disabled_regions|json }}">
|
||||
{{ region_form.regions }}
|
||||
</div>
|
||||
{% if region_form.disabled_regions %}
|
||||
{% include 'developers/payments/includes/regions_disabled.html' %}
|
||||
{% endif %}
|
||||
<div class="other-regions">
|
||||
{% include 'developers/payments/includes/regions_other.html' %}
|
||||
</div>
|
||||
<button>{{ _('Save Changes') }}</button>
|
||||
</section>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if is_paid %}
|
||||
<div id="paid-upsell-island">
|
||||
{{ disabled_payments_notice() }}
|
||||
<h2>{{ _('Promote as upgrade to free version') }}</h2>
|
||||
<section class="island upsell">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>
|
||||
{{ tip(_('This is a paid upgrade of'),
|
||||
|
@ -157,72 +274,14 @@
|
|||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><label data-for="accounts">{{ _('Payment Account') }}</label>
|
||||
</th>
|
||||
<td>
|
||||
<div id="bango-account-list" data-url="{{ url('mkt.developers.bango.payment_accounts_form') }}">
|
||||
{{ bango_account_list_form.errors }}
|
||||
{% include 'developers/payments/includes/bango_accounts_form.html' %}
|
||||
</div>
|
||||
<a href="#" class="payment-account-actions" data-action="add">
|
||||
{{- _('Add or manage payment accounts') -}}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="listing-footer">
|
||||
<button>{{ _('Save Changes') }}</button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<h2>{{ _('Regions and listings') }}</h2>
|
||||
{% if region_form.has_inappropriate_regions() %}
|
||||
<div class="island warning">
|
||||
{% trans %}
|
||||
Your app will no longer be listed in certain regions because those
|
||||
regions do not support payments. We have transferred your region
|
||||
choices. Please review the changes before saving.
|
||||
{% endtrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<section id="regions" class="island">
|
||||
{{ region_form.non_field_errors() }}
|
||||
{{ region_form.regions.label }}
|
||||
<p class="toggles">
|
||||
<a href="#" class="all">{{ _('Select All') }}</a> ·
|
||||
<a href="#" class="none">{{ _('None') }}</a>
|
||||
</p>
|
||||
{{ region_form.regions.errors }}
|
||||
<div class="checkbox-choices"
|
||||
data-disabled="{{ region_form.disabled_regions|json }}">
|
||||
{{ region_form.regions }}
|
||||
</div>
|
||||
{% if region_form.disabled_regions %}
|
||||
<p class="note disabled-regions">
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Apps/Marketplace_Review" target="_blank">
|
||||
{{ _('Learn why some regions are restricted.') }}</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
<div class="other-regions">
|
||||
{{ region_form.other_regions }}
|
||||
{{ region_form.other_regions.label_tag() }}
|
||||
{{ region_form.other_regions.errors }}
|
||||
<div class="hint note">
|
||||
{%- trans %}
|
||||
Your app will be displayed in the worldwide Marketplace and
|
||||
in any regional marketplace that is added in the future.
|
||||
You will receive an email notification when a new region
|
||||
is added.
|
||||
{% endtrans -%}
|
||||
</div>
|
||||
</div>
|
||||
<button>{{ _('Save Changes') }}</button>
|
||||
</section>
|
||||
</form>
|
||||
</section>
|
||||
{% include 'developers/includes/addons_edit_nav.html' %}
|
||||
|
|
|
@ -273,6 +273,25 @@ class TestPayments(amo.tests.TestCase):
|
|||
self.assert3xx(res, self.url)
|
||||
eq_(self.get_webapp().premium_type, amo.ADDON_PREMIUM)
|
||||
|
||||
def test_check_api_url_in_context(self):
|
||||
self.webapp.update(premium_type=amo.ADDON_FREE)
|
||||
res = self.client.get(self.url)
|
||||
eq_(res.context['api_pricelist_url'],
|
||||
reverse('api_dispatch_list', kwargs={'resource_name': 'prices',
|
||||
'api_name': 'webpay'}))
|
||||
|
||||
def test_regions_display_free(self):
|
||||
self.webapp.update(premium_type=amo.ADDON_FREE)
|
||||
res = self.client.get(self.url)
|
||||
self.assertIn('id="regions-island"', res.content)
|
||||
self.assertNotIn('id="paid-regions-island"', res.content)
|
||||
|
||||
def test_regions_display_premium(self):
|
||||
self.webapp.update(premium_type=amo.ADDON_PREMIUM)
|
||||
res = self.client.get(self.url)
|
||||
self.assertIn('id="paid-regions-island"', res.content)
|
||||
self.assertNotIn('id="regions-island"', res.content)
|
||||
|
||||
def test_premium_in_app_passes(self):
|
||||
self.webapp.update(premium_type=amo.ADDON_FREE)
|
||||
res = self.client.post(
|
||||
|
|
|
@ -134,7 +134,10 @@ def payments(request, addon_id, addon, webapp=False):
|
|||
# Waffles
|
||||
'payments_enabled':
|
||||
waffle.flag_is_active(request, 'allow-b2g-paid-submission') and
|
||||
not waffle.switch_is_active('disabled-payments')})
|
||||
not waffle.switch_is_active('disabled-payments'),
|
||||
'api_pricelist_url':
|
||||
reverse('api_dispatch_list', kwargs={'resource_name': 'prices',
|
||||
'api_name': 'webpay'})})
|
||||
|
||||
|
||||
@login_required
|
||||
|
|
Загрузка…
Ссылка в новой задаче