Merge pull request #1095 from muffinresearch/remove-region-restriction-paid

Don't restrict regions for paid (bug 904157)
This commit is contained in:
Stuart Colville 2013-09-27 11:30:18 -07:00
Родитель 660e358b54 43ddbc6da5
Коммит 1bb5a3816b
16 изменённых файлов: 279 добавлений и 865 удалений

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

@ -437,7 +437,7 @@ label.disabled {
padding-bottom: 0;
}
.regions {
.devhub-form table .regions {
.region-heading {
display: block;
hidetext();
@ -449,4 +449,25 @@ label.disabled {
td .local-retail {
display: block;
}
table td {
line-height: 1.5em;
min-height: 1.5em;
padding: 1em 0;
}
}
.paid-regions {
margin-bottom: 10px;
}
body > label {
font-weight: normal;
}
.note p:only-child {
margin-bottom: 1em;
}
.region-choices li {
min-height: 19px;
}

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

@ -5,16 +5,18 @@ define('payments', [], function() {
var $regions = $('#region-list');
var $regionsIsland = $('#regions');
var $regionCheckboxes = $regions.find('input[type=checkbox]');
var $regionsChangedWarning = $('#regions-changed');
var $regionsInappropriateWarning = $('#regions-inappropriate');
var $before = $regions.find('input[type=checkbox]:disabled');
var apiErrorMsg = $regions.data('apiErrorMsg');
var disabledGeneralRegions = $regions.data('disabledGeneralRegions');
var tierZeroId = $regions.data('tierZeroId');
var notApplicableMsg = $regions.data('notApplicableMsg');
var paymentMethods = $regions.data('paymentMethods') || {};
var pricesApiEndpoint = $regions.data('pricelistApiUrl') + '{0}/';
var regionsData = $regions.data();
var allPaidRegionIds = regionsData.allPaidRegionIds;
var apiErrorMsg = regionsData.apiErrorMsg;
var disabledRegions = regionsData.disabledRegions;
var tierZeroId = regionsData.tierZeroId;
var notApplicableMsg = regionsData.notApplicableMsg;
var paymentMethods = regionsData.paymentMethods || {};
var pricesApiEndpoint = regionsData.pricelistApiUrl + '{0}/';
var $tdNodes = $('<td class="cb"></td><td class="lp"></td><td class="lm"></td>');
var $paidRegionTableTbody = $('#paid-regions tbody');
function getOverlay(opts) {
var id = opts;
@ -83,6 +85,42 @@ define('payments', [], function() {
}));
}
function moveAnimate(element, newParent, $elmToRemove, zIndex) {
zIndex = zIndex || 100;
var $element = $(element);
var $newParent = $(newParent);
var oldOffset = $element.offset();
$element.appendTo($newParent);
var newOffset = $element.offset();
var $temp = $element.clone().appendTo('body');
$temp.css({'position': 'absolute',
'left': oldOffset.left,
'top': oldOffset.top,
'zIndex': zIndex});
element.hide();
$temp.animate({'top': parseInt(newOffset.top, 10), 'left': parseInt(newOffset.left, 10) }, 'slow', function(){
$temp.remove();
$element.show();
if ($elmToRemove) {
$elmToRemove.hide(500, function() { this.remove(); });
}
});
}
function createTableRow(checkBox, ident, localPriceText, localMethodText) {
var $tds = $tdNodes.clone();
var $tr = $paidRegionTableTbody.find('tr[data-region="' + ident + '"]');
var $checkBoxContainer = $($tds[0]);
var $localPriceContainer = $($tds[1]);
var $localMethodContainer = $($tds[2]);
$localMethodContainer.text(localMethodText);
$localPriceContainer.text(localPriceText);
$tr.append($tds);
return $tr;
}
function disableCheckbox() {
/*jshint validthis:true */
var $this = $(this);
@ -94,57 +132,14 @@ define('payments', [], function() {
$this.closest('tr').find('.local-retail, .local-method').text('');
}
function compareDisabledCheckboxes($before) {
var hasChanged = false;
var $after = $regions.find('input[type=checkbox]:disabled');
if ($before.length && $after.length && $before.length === $after.length) {
$after.each(function() {
// If current element isn't in $before the state has changed and we can
// exit the each.
var beforeIndex = $.inArray(this, $before);
if (beforeIndex === -1) {
hasChanged = true;
return false;
// As soon as a disabled prop doesn't match flag the change and exit each.
} else if ($(this).prop('disabled') !== $($before[beforeIndex]).prop('disabled')) {
hasChanged = true;
return false;
}
});
} else if (($before.length || $after.length) && $before.length !== $after.length) {
hasChanged = true;
}
if (hasChanged) {
$regionsChangedWarning.removeClass('hidden');
} else {
$regionsChangedWarning.addClass('hidden');
}
}
function updatePrices(checkForChanges) {
function updatePrices() {
/*jshint validthis:true */
var $this = $(this);
var selectedPrice = $this.val();
checkForChanges = checkForChanges === false ? checkForChanges : true;
// Check for NaN which will be caused by selectedPrice being ''.
if (selectedPrice != 'free') {
selectedPrice = parseInt(selectedPrice, 10);
selectedPrice = isNaN(selectedPrice) ? false : selectedPrice;
}
// No-op if nothing has changed.
if (currentPrice === selectedPrice) {
return;
}
// Handle the 'Please select a price' case.
if (selectedPrice === false) {
$regionCheckboxes.each(disableCheckbox);
currentPrice = selectedPrice;
if (!selectedPrice) {
return;
}
@ -154,73 +149,80 @@ define('payments', [], function() {
$('input[name=allow_inapp][value=True]').prop('checked', true);
$('input[name=allow_inapp][value=False]').prop('disabled', true)
.parent('label').hide();
// Enable all the checkboxes save for those that should be disabled.
// e.g. unrated games in Brazil.
$regionCheckboxes.each(function() {
$this = $(this);
if (disabledGeneralRegions.indexOf(parseInt($this.prop('value'), 10)) === -1) {
$this.prop('disabled', false).closest('label').removeClass('disabled')
.closest('tr').find('.local-method, .local-retail')
.text(notApplicableMsg);
} else {
disableCheckbox.call(this);
}
});
$('#paid-upsell-island').hide();
currentPrice = selectedPrice;
if (checkForChanges) {
compareDisabledCheckboxes($before);
}
return;
// For free apps we are using the same data for tier zero apps
// to populate the region list.
selectedPrice = tierZeroId;
} else {
$('#paid-upsell-island').show();
$('input[name=allow_inapp][value=False]').prop('disabled', false)
.parent('label').show();
}
// From here on numbers should be used.
selectedPrice = parseInt(selectedPrice, 10);
// No-op if nothing else has changed.
if (currentPrice === selectedPrice) {
return;
}
$.ajax({
url: format(pricesApiEndpoint, selectedPrice),
beforeSend: function() {
$regionsIsland.addClass('loading');
},
success: function(data) {
var moveQueue = [];
var prices = data.prices || [];
var tierPrice = data.price;
var seen = [];
var tierPrice = data.price;
// 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 regionId = price.region;
var billingMethodText = paymentMethods[parseInt(price.method, 10)] || '';
var $chkbox = $regions.find('input:checkbox[value=' + region + ']');
// Skip if over regions that should be disabled e.g an unrated games app in Brazil.
if (disabledGeneralRegions.indexOf(region) > -1) {
continue;
var localPrice = price.price + ' ' + price.currency;
var localMethod = selectedPrice === tierZeroId ? notApplicableMsg : billingMethodText;
// If the checkbox we're interested is already in the table just update it.
// Otherwise we need to create a new tableRow and move it into position.
var $chkbox = $regions.find('input:checkbox[value=' + regionId + ']');
var $row = $('#paid-regions tr[data-region=' + regionId + ']');
if ($row.find('td').length) {
$row.find('.lp').text(localPrice);
$row.find('.lm').text(localMethod);
} else {
var $tr = createTableRow($chkbox.closest('label'), regionId, localPrice, localMethod);
moveQueue.push([$chkbox.closest('label'), $tr.find('.cb')]);
$chkbox.closest('li').hide(500);
}
// Enable checkboxes for those that we have price info for.
$chkbox.prop('disabled', false)
.closest('label').removeClass('disabled');
var $tr = $chkbox.closest('tr');
$tr.find('.local-retail')
.text(price.price + ' ' + price.currency);
$tr.find('.local-method')
.text(selectedPrice === tierZeroId ? notApplicableMsg : billingMethodText);
seen.push($chkbox[0]);
}
// Disable everything else.
$regionCheckboxes.not(seen).each(disableCheckbox);
if (checkForChanges) {
compareDisabledCheckboxes($before);
for (var k=0, l=moveQueue.length; k<l; k++) {
var current = moveQueue[k];
moveAnimate(current[0], current[1]);
}
$('#paid-regions input[type=checkbox]').not(seen).each(function() {
// If the item we don't want here is in the table then we need to move it back
// out of the table and destroy the row contents.
var $chkbox = $(this);
var region = $chkbox.val();
// Lookup the location of the original checkbox so we know where to send this back to
var $newParent = $('.checkbox-choices li[data-region=' + region + ']');
$newParent.show(500);
var $label = $chkbox.closest('label');
if ($label.length) {
var $tds = $chkbox.closest('tr').find('td');
moveAnimate($label, $newParent, $tds);
}
});
},
dataType: "json"
}).fail(function() {
@ -250,7 +252,7 @@ define('payments', [], function() {
// Only update if we can edit. If the user can't edit all fields will be disabled.
if (!z.body.hasClass('no-edit')) {
$priceSelect.on('change', updatePrices);
updatePrices.call($priceSelect[0], false);
updatePrices.call($priceSelect[0]);
}
}

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

@ -200,12 +200,15 @@ REGIONS_CHOICES = (
BY_SLUG = sorted([v for k, v in DEFINED if v.id and v.weight > -1],
key=lambda v: v.slug)
REGIONS_CHOICES_SLUG = ([('worldwide', WORLDWIDE)] +
[(v.slug, v) for v in BY_SLUG])
REGIONS_CHOICES_ID = ([(WORLDWIDE.id, WORLDWIDE)] +
[(v.id, v) for v in BY_SLUG])
REGIONS_CHOICES_NAME = ([(WORLDWIDE.id, WORLDWIDE.name)] +
[(v.id, v.name) for v in BY_SLUG])
# Worldwide last here so we can display it after all the other regions.
REGIONS_CHOICES_NAME = ([(v.id, v.name) for v in BY_SLUG] +
[(WORLDWIDE.id, WORLDWIDE.name)])
REGIONS_DICT = dict(REGIONS_CHOICES)
REGIONS_CHOICES_ID_DICT = dict(REGIONS_CHOICES_ID)
@ -214,4 +217,9 @@ ALL_PAID_REGIONS = frozenset(r for r in ALL_REGIONS if r.has_payments)
ALL_REGION_IDS = sorted(REGIONS_CHOICES_ID_DICT.keys())
ALL_PAID_REGION_IDS = sorted(r.id for r in ALL_PAID_REGIONS)
ALL_PAID_REGIONS_BY_SLUG = sorted(ALL_PAID_REGIONS,
key=lambda x: getattr(x, 'slug', None))
ALL_PAID_REGION_IDS_BY_SLUG = [r.id for r in ALL_PAID_REGIONS_BY_SLUG]
# Regions not including worldwide.
REGION_IDS = sorted(REGIONS_CHOICES_ID_DICT.keys())[1:]

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

@ -44,7 +44,6 @@ from mkt.constants import MAX_PACKAGED_APP_SIZE
from mkt.constants.ratingsbodies import (ALL_RATINGS, RATINGS_BODIES,
RATINGS_BY_NAME)
from mkt.site.forms import AddonChoiceField
from mkt.regions import ALL_PAID_REGION_IDS, ALL_REGION_IDS
from mkt.webapps.models import AddonExcludedRegion, ContentRating, Webapp
from mkt.webapps.tasks import index_webapps
from mkt.zadmin.models import FeaturedApp
@ -669,105 +668,44 @@ class AppAppealForm(happyforms.Form):
class RegionForm(forms.Form):
regions = forms.MultipleChoiceField(required=False,
label=_lazy(u'Choose the regions your app will be listed in:'),
choices=mkt.regions.REGIONS_CHOICES_NAME[1:],
choices=mkt.regions.REGIONS_CHOICES_NAME,
widget=forms.CheckboxSelectMultiple,
error_messages={'required':
_lazy(u'You must select at least one region.')})
other_regions = forms.BooleanField(required=False, initial=True,
label=_lazy(u'Other and new regions'))
enable_new_regions = forms.BooleanField(required=False,
label=_lazy(u'Enable new regions'))
def __init__(self, *args, **kw):
self.product = kw.pop('product', None)
self.request = kw.pop('request', None)
self.price = kw.pop('price', None)
self.region_ids = self.product.get_region_ids()
self.region_ids = self.product.get_region_ids(worldwide=True)
super(RegionForm, self).__init__(*args, **kw)
# Initialise the price for free_inapp.
if not self.price and self.product and self.product.is_free_inapp():
self.price = 'free'
is_paid = self._product_is_paid()
# If we have excluded regions, uncheck those.
# Otherwise, default to everything checked.
self.regions_before = self.product.get_region_ids()
self.regions_before = self.product.get_region_ids(worldwide=True)
# If we have future excluded regions, uncheck box.
# Note: this is currently only relevant for non-paid apps.
self.future_exclusions = self.product.addonexcludedregion.filter(
region=mkt.regions.WORLDWIDE.id)
self.future_exclusions = self.product.enable_new_regions
self.initial = {
'regions': self.regions_before,
'enable_new_regions': self.product.enable_new_regions,
}
# If the app is paid, disable regions that use payments.
if is_paid:
# For paid apps enabling new regions is not based on the worldwide
# region it's based on enable_new_regions.
self.fields['other_regions'].label = _(u'Enable new regions')
self.initial['other_regions'] = self.product.enable_new_regions
# Premium form was valid.
if self.price and self.price != 'free':
self.price_region_ids = (self.price.pricecurrency_set
.values_list('region', flat=True))
# Free app with in-app payments for this we just want to make
# sure it's in a region that allows payments.
# self.price is intialised above for free_inapp even if
# this isn't a post.
elif self.price and self.price == 'free':
self.price_region_ids = ALL_PAID_REGION_IDS
# Premium form wasn't valid and it is a POST. Since we can't
# determine what price they wanted, just make sure it isn't a
# disabled price.
elif self.data:
self.price_region_ids = []
# Not a post, we can trust the price on the product.
else:
self.price_region_ids = (self.product
.get_possible_price_region_ids())
else:
# Set initial of other_regions for non-paid apps.
self.initial['other_regions'] = (not
self.future_exclusions.exists())
# These are split out so we can distinguish regions that are totally
# disabled vs those that are disabled based on price.
self.disabled_general_regions = sorted(
self._disabled_general_regions())
self.disabled_regions = sorted(self._disabled_regions())
def _disabled_regions(self):
"""All disabled regions (varys based on current price)."""
return self._disabled_general_regions().union(
self._disabled_paid_regions())
def _disabled_general_regions(self):
"""Regions that are disabled for general reasons."""
disabled_general_regions = set()
disabled_regions = set()
# Games cannot be listed in Brazil without a content rating.
games = Webapp.category('games')
if (games and
self.product.categories.filter(id=games.id).exists() and
not self.product.content_ratings_in(mkt.regions.BR)):
disabled_general_regions.add(mkt.regions.BR.id)
disabled_regions.add(mkt.regions.BR.id)
return disabled_general_regions
def _disabled_paid_regions(self):
"""Regions disabled based on current price."""
dpr = set()
if self._product_is_paid():
# Ensure price_regions are in ALL_PAID_REGION_IDS.
valid_price_regions = (set(self.price_region_ids).intersection(
set(ALL_PAID_REGION_IDS)))
dpr = set(ALL_REGION_IDS).difference(valid_price_regions)
return dpr
return disabled_regions
def is_toggling(self):
if not self.request or not hasattr(self.request, 'POST'):
@ -779,29 +717,11 @@ class RegionForm(forms.Form):
return (self.product.premium_type in amo.ADDON_PREMIUMS
or self.product.premium_type == amo.ADDON_FREE_INAPP)
def has_inappropriate_regions(self):
"""Returns whether the app is listed in regions that it shouldn't
otherwise be registered in."""
if self._product_is_paid():
return set(self.region_ids).intersection(
set(self.disabled_regions))
def clean(self):
data = self.cleaned_data
if (not data.get('regions') and not data.get('other_regions')
and not self.is_toggling()):
if (not data.get('regions') and not self.is_toggling()):
raise forms.ValidationError(
_('You must select at least one region or '
'"Other and new regions."'))
if data.get('regions'):
self.region_ids = [int(r) for r in data['regions']]
if self.has_inappropriate_regions():
raise forms.ValidationError(
_('You have selected a region that is not valid for your '
'price point.'))
_('You must select at least one region.'))
return data
def save(self):
@ -812,10 +732,6 @@ class RegionForm(forms.Form):
before = set(self.regions_before)
after = set(map(int, self.cleaned_data['regions']))
# If the app is paid, disable regions that do not use payments.
if self._product_is_paid():
after &= set(self.price_region_ids)
# Add new region exclusions.
to_add = before - after
for r in to_add:
@ -832,33 +748,14 @@ class RegionForm(forms.Form):
log.info(u'[Webapp:%s] No longer exluded from region (%s).'
% (self.product, r))
if self.cleaned_data['other_regions']:
# For a paid app enable_new_regions is distinct from
# the worldwide region.
if self._product_is_paid():
self.product.update(enable_new_regions=True)
log.info(u'[Webapp:%s] will be added to future regions.'
% self.product)
else:
# Developer wants to be visible in future regions, then
# delete excluded regions.
self.future_exclusions.delete()
log.info(u'[Webapp:%s] No longer excluded from future regions.'
if self.cleaned_data['enable_new_regions']:
self.product.update(enable_new_regions=True)
log.info(u'[Webapp:%s] will be added to future regions.'
% self.product)
else:
if self._product_is_paid():
self.product.update(enable_new_regions=False)
log.info(u'[Webapp:%s] will not be added to future regions.'
self.product.update(enable_new_regions=False)
log.info(u'[Webapp:%s] will not be added to future regions.'
% self.product)
else:
# Developer does not want future regions, then
# exclude all future apps.
g, c = AddonExcludedRegion.objects.get_or_create(
addon=self.product, region=mkt.regions.WORLDWIDE.id)
if c:
log.info(u'[Webapp:%s] Excluded from future regions.'
% self.product)
ban_game_in_brazil(self.product)

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

@ -104,7 +104,6 @@ class PremiumForm(DeviceTypeForm, happyforms.Form):
def group_tier_choices(self):
"""Creates tier choices with optgroups based on payment methods"""
price_choices = [
('', _('Please select a price')),
('free', _('Free (with in-app payments)')),
]
card_billed = []

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

@ -1,161 +0,0 @@
from optparse import make_option
from django.core.management.base import BaseCommand, CommandError
import amo
from mkt.developers.forms import RegionForm
from mkt.regions import ALL_REGION_IDS, REGIONS_CHOICES_ID_DICT
from mkt.webapps.models import AddonExcludedRegion as AER, Webapp
ALL_REGIONS = set(ALL_REGION_IDS)
DIVIDER = '-' * 28
class Command(BaseCommand):
args = '<app_slug>'
option_list = BaseCommand.option_list + (
make_option('--exclude_region_by_id', action='store',
type='int', dest='exclude_region_id',
help='Adds an exclusion record for a region by id'),
make_option('--include_region_by_id', action='store',
type='int', dest='include_region_id',
help='Removes an exclusion record for a region by id'),
)
help = ('Check regions for a given paid app and flag if they have '
'incorrect regions.')
def _region_obj(self, id_):
return REGIONS_CHOICES_ID_DICT.get(id_)
def _region_name(self, id_):
region_obj_ = self._region_obj(id_)
return unicode(region_obj_.name)
def write_output(self, value=''):
self.stdout.write(value + '\n')
def write_error(self, value=''):
self.stderr.write(value + '\n')
def get_regions(self, app):
region_excludes = (AER.objects.filter(addon=app)
.values_list('region', flat=True))
return ALL_REGIONS.difference(region_excludes)
def get_bad_regions(self, app, regions):
# Initialise RegionForm so we can get the disabled region data
# based on our app.
if app.premium_type == amo.ADDON_FREE_INAPP:
price = 'free'
else:
price = app.premium.price
region_form = RegionForm(data={'regions': regions},
product=app, price=price)
# We manually construct bad_regions so we can make sure we catch
# worldwide regions (Worldwide is not a valid choice in the form).
return regions.intersection(region_form.disabled_regions)
def exclude_region(self, app, app_slug, exclude_region_id):
aer, created = AER.objects.get_or_create(addon=app,
region=exclude_region_id)
if not created:
self.write_error('Could not create exclusion record for '
'region_id %s (%s). It already exists' % (
exclude_region_id,
self._region_name(exclude_region_id)))
else:
self.write_output('')
self.write_output("Excluding from region_id %s (%s) for "
"app '%s'" % (exclude_region_id,
self._region_name(exclude_region_id),
app_slug))
self.include_exclude_region = True
def include_region(self, app, app_slug, include_region_id):
self.write_output()
self.write_output("Including from region_id %s (%s) for app "
"'%s'" % (include_region_id,
self._region_name(include_region_id),
app_slug))
try:
aer = AER.objects.get(addon=app, region=include_region_id)
aer.delete()
self.include_exclude_region = True
except AER.DoesNotExist:
self.write_error('Could not remove exclusion record for '
'region_id %s (%s)' % (include_region_id,
self._region_name(include_region_id)))
def output_regions(self, app, app_slug):
regions = self.get_regions(app)
bad_regions = self.get_bad_regions(app, regions)
self.write_output('App Slug: %s' % app_slug)
self.write_output('App Status: %s' % unicode(
amo.STATUS_CHOICES.get(app.status)))
self.write_output('App Id: %s' % app.pk)
self.write_output(DIVIDER)
self.write_output('id | region.name')
self.write_output(DIVIDER)
has_bad_region = False
for region_id in regions:
region_name = self._region_name(region_id)
asterisk = ''
if region_id in bad_regions:
has_bad_region = True
asterisk = ' *'
self.write_output('%s | %s%s' % (str(region_id).ljust(2),
region_name, asterisk))
if has_bad_region:
self.write_output('* Inappropriate region')
def handle(self, *args, **options):
self.include_exclude_region = False
if not args:
raise CommandError('An app_slug is required.')
if len(args) > 1:
raise CommandError('Only a single app_slug is accepted.')
app_slug = args[0]
# Look up the app by slug.
try:
app = Webapp.objects.get(app_slug=app_slug,
premium_type__in=amo.ADDON_HAS_PAYMENTS)
except Webapp.DoesNotExist:
raise CommandError('Paid app with slug %s not '
'found.' % app_slug)
# Bail if the app doesn't have a price.
if (app.premium_type != amo.ADDON_FREE_INAPP and
not app.has_premium() and
not getattr('app.premium', 'price', False)):
raise CommandError("App %s doesn't have a price" % app_slug)
# Outputs the region info.
self.output_regions(app, app_slug)
# Handle including a region by deleting an exlusion record for the app.
include_region_id = options.get('include_region_id')
if include_region_id:
self.include_region(app, app_slug, include_region_id)
# Handle an exclusions record by adding an exclusion record for
# the app.
exclude_region_id = options.get('exclude_region_id')
if exclude_region_id:
self.exclude_region(app, app_slug, exclude_region_id)
# If we've include/excluded a region show the regions now.
if self.include_exclude_region:
self.write_output()
self.write_output('Regions are now as follows:')
self.output_regions(app, app_slug)

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

@ -0,0 +1,20 @@
{{ region_form.regions.errors }}
<div class="checkbox-choices region-choices"{% if not is_paid %} id="region-list" data-disabled-regions="{{ region_form.disabled_regions|json }}"{% endif %}>
<ul>
{% for value, text in region_form.regions.field.choices %}
<li data-region="{{ value }}">
<label class="region-cb{% if value in region_form.disabled_regions %} disabled{% endif %}">
<input type="checkbox"
{% if value in region_form.disabled_regions %}disabled{% endif %}
{% if value in region_form.initial.regions %}checked{% endif %}
name="regions" value="{{ value }}">{{ text }}</label>
</li>
{% endfor %}
</ul>
</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>

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

@ -1,20 +1,10 @@
{{ region_form.other_regions }}
{{ region_form.other_regions.label_tag() }}
{{ region_form.other_regions.errors }}
{{ region_form.enable_new_regions }}
{{ region_form.enable_new_regions.label_tag() }}
{{ region_form.enable_new_regions.errors }}
<div class="hint note">
{% if region_form._product_is_paid() %}
{%- trans %}
Your app will be displayed in any regional Marketplace that is
added in the future.
You will receive an email notification when a new region
is added.
{% endtrans -%}
{% else %}
{%- 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 -%}
{% endif %}
{{ _('Your app will be displayed in any regional Marketplace that is added in the future.')}}
{% if region_form._product_is_paid() %}
<em>{{ _('(Subject to payments being available in that region for the selected price point).') }}</em>
{% endif %}
{{ _('You will receive an email notification when a new region is added.') }}
</div>

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

@ -144,17 +144,6 @@
<div id="paid-regions-island">
<h2>{{ _('Prices and countries') }}</h2>
{% if region_form.has_inappropriate_regions() %}
{% include 'developers/payments/includes/regions_inappropriate.html' %}
{% endif %}
<div class="island info hidden" id="regions-changed">
{%- trans %}
Based on your chosen price point the available regions have been updated.
Please check them prior to saving your changes.
{% endtrans -%}
</div>
<section id="regions" class="island">
<table>
<tbody>
@ -175,63 +164,57 @@
{{ 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 id="region-list" class="checkbox-choices regions"
data-api-error-msg="{{ _('A server error occurred. Please try again later.') }}"
data-disabled-general-regions="{{ region_form.disabled_general_regions|json }}"
data-disabled-regions="{{ region_form.disabled_regions|json }}"
data-all-paid-region-ids="{{ all_paid_region_ids_by_slug|json }}"
data-not-applicable-msg="{{ _('Not applicable') }}"
data-payment-methods="{{ payment_methods|json }}"
data-pricelist-api-url="{{ api_pricelist_url }}"
data-tier-zero-id="{{ tier_zero_id }}">
{{ region_form.regions.errors }}
<table>
<thead>
<tr>
<th><span class="region-heading">{{ _('Region') }}</span></th>
<th>{{ _('Retail price') }}
<span class="local-currency-heading">({{ _('local currency') }})</span></th>
<th>{{ _('Billing method') }}</th>
</tr>
</thead>
<tbody>
{% for value, text in region_form.regions.field.choices %}
{% if value|int in mkt.regions.ALL_PAID_REGION_IDS %}
{% include 'developers/payments/includes/regions_toggle.html' %}
<div class="paid-regions">
<h3>{{ _('Available Regions') }}</h3>
<div class="hint note">
<p>{{ _('Your app will be available in the following selected regions:') }}</p>
</div>
<table id="paid-regions">
<thead>
<tr>
<td>
<label {% if value in region_form.disabled_regions %} class="disabled"{% endif %}>
<input type="checkbox"
{% if value in region_form.disabled_regions %}disabled{% endif %}
{% if value in region_form.initial.regions %}checked{% endif %}
name="regions" value="{{ value }}">{{ text }}</label>
</td>
<td><span class="local-retail"></span></td>
<td><span class="local-method"></span></td>
<th><span class="region-heading">{{ _('Region') }}</span></th>
<th>{{ _('Retail price') }}
<span class="local-currency-heading">({{ _('local currency') }})</span></th>
<th>{{ _('Billing method') }}</th>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</thead>
<tbody class="checkbox-choices">
{% for id in all_paid_region_ids_by_slug %}
<tr data-region="{{ id }}"></tr>
{% endfor %}
</tbody>
</table>
</div>
<h3>{{ _("Other regions") }}</h3>
<div class="hint note">
<p>
{% trans %}
Your app will be available in the following selected regions in the future when payments are available based on your chosen price point.
To exclude your app from appearing in a region please un-check that region before saving.
{% endtrans %}
</p>
</div>
{% include 'developers/payments/includes/region_form.html' %}
</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">
@ -243,22 +226,9 @@
{# 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>
{% include 'developers/payments/includes/region_form.html' %}
<button>{{ _('Save Changes') }}</button>
</section>
</div>

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

@ -16,7 +16,6 @@ from amo.tests import app_factory, version_factory
from amo.tests.test_helpers import get_image_path
from addons.models import Addon, AddonCategory, Category, CategorySupervisor
from files.helpers import copyfileobj
from market.models import AddonPremium, Price
from tags.models import Tag
from users.models import UserProfile
@ -151,7 +150,7 @@ class TestCategoryForm(amo.tests.WebappTestCase):
class TestRegionForm(amo.tests.WebappTestCase):
fixtures = fixture('webapp_337141', 'prices')
fixtures = fixture('webapp_337141')
def setUp(self):
super(TestRegionForm, self).setUp()
@ -160,254 +159,76 @@ class TestRegionForm(amo.tests.WebappTestCase):
def test_initial_empty(self):
form = forms.RegionForm(data=None, **self.kwargs)
eq_(form.initial['regions'], mkt.regions.REGION_IDS)
eq_(form.initial['other_regions'], True)
eq_(form.initial['regions'], mkt.regions.ALL_REGION_IDS)
eq_(form.initial['enable_new_regions'], False)
def test_initial_excluded_in_region(self):
AER.objects.create(addon=self.app, region=mkt.regions.BR.id)
regions = list(mkt.regions.REGION_IDS)
regions = list(mkt.regions.ALL_REGION_IDS)
regions.remove(mkt.regions.BR.id)
eq_(self.get_app().get_region_ids(), regions)
eq_(self.get_app().get_region_ids(worldwide=True), regions)
form = forms.RegionForm(data=None, **self.kwargs)
eq_(form.initial['regions'], regions)
eq_(form.initial['other_regions'], True)
eq_(form.initial['enable_new_regions'], False)
def test_initial_excluded_in_regions_and_future_regions(self):
for region in [mkt.regions.BR, mkt.regions.UK, mkt.regions.WORLDWIDE]:
AER.objects.create(addon=self.app, region=region.id)
regions = list(mkt.regions.REGION_IDS)
regions = list(mkt.regions.ALL_REGION_IDS)
regions.remove(mkt.regions.BR.id)
regions.remove(mkt.regions.UK.id)
regions.remove(mkt.regions.WORLDWIDE.id)
eq_(self.get_app().get_region_ids(), regions)
form = forms.RegionForm(data=None, **self.kwargs)
eq_(form.initial['regions'], regions)
eq_(form.initial['other_regions'], False)
@mock.patch('mkt.regions.BR.has_payments', new=True)
def test_disable_regions_on_paid(self):
eq_(self.app.get_region_ids(), mkt.regions.REGION_IDS)
self.app.update(premium_type=amo.ADDON_PREMIUM)
price = Price.objects.get(id=1)
AddonPremium.objects.create(addon=self.app,
price=price)
self.kwargs['price'] = price
form = forms.RegionForm(data=None, **self.kwargs)
assert not form.is_valid()
assert form.has_inappropriate_regions()
form = forms.RegionForm(
data={'regions': mkt.regions.ALL_PAID_REGION_IDS}, **self.kwargs)
assert not form.is_valid()
assert form.has_inappropriate_regions()
form = forms.RegionForm(data={'regions': [mkt.regions.PL.id]},
**self.kwargs)
assert form.is_valid(), form.errors
assert not form.has_inappropriate_regions()
form.save()
self.assertSetEqual(self.app.get_region_ids(),
[mkt.regions.PL.id])
@mock.patch('mkt.developers.forms.ALL_PAID_REGION_IDS',
new=[3, 4, 5])
@mock.patch('mkt.developers.forms.ALL_REGION_IDS',
new=[1, 2, 3, 4, 5, 6])
def test_inappropriate_regions(self):
self.app.update(premium_type=amo.ADDON_PREMIUM)
form = forms.RegionForm(data=None, **self.kwargs)
form.price_region_ids = [2, 3, 5]
# Reset disabled_regions as we're modifying price_regions.
form.disabled_regions = form._disabled_regions()
# 6 is not in price_region_ids or ALL_PAID_REGION_IDS
form.region_ids = [6]
assert form.has_inappropriate_regions(), 'Region 6 should be invalid'
# Worldwide (1) is disabled for paid apps presently.
form.region_ids = [mkt.regions.WORLDWIDE.id]
assert form.has_inappropriate_regions(), 'Worldwide region should be invalid'
# 4 is not in price_region_ids so should be invalid.
form.region_ids = [4]
assert form.has_inappropriate_regions(), 'Region 4 should be invalid'
# 2 is in price_region_ids but not in ALL_PAID_REGION_IDS
# so should be invalid.
form.region_ids = [2]
assert form.has_inappropriate_regions(), 'Region 2 should be invalid'
# 3 is in price_region_ids and in ALL_PAID_REGION_IDS so should be ok.
form.region_ids = [3]
assert not form.has_inappropriate_regions(), 'Region 3 should be valid'
def test_inappropriate_regions_free_app(self):
self.app.update(premium_type=amo.ADDON_FREE)
form = forms.RegionForm(data=None, **self.kwargs)
eq_(form.has_inappropriate_regions(), None)
@mock.patch('mkt.developers.forms.ALL_PAID_REGION_IDS',
new=[2, 3, 4, 5])
@mock.patch('mkt.developers.forms.ALL_REGION_IDS',
new=[1, 2, 3, 4, 5, 6])
def test_disabled_regions_premium(self):
self.app.update(premium_type=amo.ADDON_PREMIUM)
form = forms.RegionForm(data=None, **self.kwargs)
form.price_region_ids = [2, 3, 5]
# Worldwide (1) is disabled for paid apps curently.
self.assertSetEqual(form._disabled_regions(), [1, 4, 6])
@mock.patch('mkt.developers.forms.ALL_PAID_REGION_IDS',
new=[2, 3, 4, 5])
@mock.patch('mkt.developers.forms.ALL_REGION_IDS',
new=[1, 2, 3, 4, 5, 6])
def test_disabled_regions_free_inapp(self):
self.app.update(premium_type=amo.ADDON_FREE_INAPP)
form = forms.RegionForm(data=None, **self.kwargs)
# Worldwide (1) is disabled for paid apps curently.
self.assertSetEqual(form._disabled_regions(), [1, 6])
@mock.patch('mkt.developers.forms.ALL_REGION_IDS',
new=[1, 2, 3, 4, 5, 6])
def test_disabled_regions_free(self):
self.app.update(premium_type=amo.ADDON_FREE)
form = forms.RegionForm(data=None, **self.kwargs)
self.assertSetEqual(form._disabled_regions(), [])
def test_free_inapp_with_non_paid_region(self):
# Start with a free app with in_app payments.
self.app.update(premium_type=amo.ADDON_FREE_INAPP)
self.kwargs['price'] = 'free'
form = forms.RegionForm(data=None, **self.kwargs)
assert not form.is_valid()
assert form.has_inappropriate_regions()
all_paid_regions = set(mkt.regions.ALL_PAID_REGION_IDS)
new_paid = sorted(
all_paid_regions.difference(set([mkt.regions.BR.id])))
with mock.patch('mkt.developers.forms.ALL_PAID_REGION_IDS',
new=new_paid):
form = forms.RegionForm(data={'regions': [mkt.regions.BR.id]},
**self.kwargs)
assert not form.is_valid()
assert form.has_inappropriate_regions()
new_paid = sorted(
all_paid_regions.difference(set([mkt.regions.UK.id])))
with mock.patch('mkt.developers.forms.ALL_PAID_REGION_IDS',
new=new_paid):
form = forms.RegionForm(data={'regions': [mkt.regions.UK.id]},
**self.kwargs)
assert not form.is_valid()
assert form.has_inappropriate_regions()
new_paid = sorted(
all_paid_regions.union(set([mkt.regions.PL.id])))
with mock.patch('mkt.developers.forms.ALL_PAID_REGION_IDS',
new=new_paid):
form = forms.RegionForm(data={'regions': [mkt.regions.PL.id]},
**self.kwargs)
assert form.is_valid()
assert not form.has_inappropriate_regions()
def test_premium_to_free_inapp_with_non_paid_region(self):
# At this point the app is premium.
self.app.update(premium_type=amo.ADDON_PREMIUM)
self.kwargs['price'] = 'free'
form = forms.RegionForm(data=None, **self.kwargs)
assert not form.is_valid()
assert form.has_inappropriate_regions()
all_paid_regions = set(mkt.regions.ALL_PAID_REGION_IDS)
new_paid = sorted(
all_paid_regions.difference(set([mkt.regions.BR.id])))
with mock.patch('mkt.developers.forms.ALL_PAID_REGION_IDS',
new=new_paid):
form = forms.RegionForm(data={'regions': [mkt.regions.BR.id]},
**self.kwargs)
assert not form.is_valid()
assert form.has_inappropriate_regions()
new_paid = sorted(
all_paid_regions.difference(set([mkt.regions.UK.id])))
with mock.patch('mkt.developers.forms.ALL_PAID_REGION_IDS',
new=new_paid):
form = forms.RegionForm(data={'regions': [mkt.regions.UK.id]},
**self.kwargs)
assert not form.is_valid()
assert form.has_inappropriate_regions()
new_paid = sorted(all_paid_regions.union(set([mkt.regions.PL.id])))
with mock.patch('mkt.developers.forms.ALL_PAID_REGION_IDS',
new=new_paid):
form = forms.RegionForm(data={'regions': [mkt.regions.PL.id]},
**self.kwargs)
assert form.is_valid()
assert not form.has_inappropriate_regions()
def test_paid_enable_region(self):
for region in mkt.regions.ALL_REGION_IDS:
AER.objects.create(addon=self.app, region=region)
self.app.update(premium_type=amo.ADDON_PREMIUM)
price = Price.objects.get(id=1)
AddonPremium.objects.create(addon=self.app,
price=price)
self.kwargs['price'] = price
form = forms.RegionForm(data={'regions': []}, **self.kwargs)
assert not form.is_valid() # Fails due to needing at least 1 region.
assert not form.has_inappropriate_regions(), (
form.has_inappropriate_regions())
form = forms.RegionForm(data={'regions': [mkt.regions.PL.id]},
**self.kwargs)
assert form.is_valid(), form.errors
assert not form.has_inappropriate_regions()
form = forms.RegionForm(data={'regions': [mkt.regions.BR.id]},
**self.kwargs)
assert not form.is_valid()
assert form.has_inappropriate_regions()
eq_(form.initial['enable_new_regions'], False)
def test_worldwide_only(self):
form = forms.RegionForm(data={'other_regions': 'on'}, **self.kwargs)
form = forms.RegionForm(data={'regions': [mkt.regions.WORLDWIDE.id]},
**self.kwargs)
assert form.is_valid(), form.errors
def test_enable_new_regions(self):
form = forms.RegionForm(data={'enable_new_regions': 'on',
'regions': mkt.regions.ALL_REGION_IDS},
**self.kwargs)
assert form.is_valid(), form.errors
form.save()
eq_(self.app.get_region_ids(True), [mkt.regions.WORLDWIDE.id])
eq_(self.app.enable_new_regions, True)
def test_no_regions(self):
form = forms.RegionForm(data={}, **self.kwargs)
assert not form.is_valid()
eq_(form.errors,
{'__all__': ['You must select at least one region or '
'"Other and new regions."']})
{'__all__': ['You must select at least one region.']})
def test_exclude_each_region(self):
"""Test that it's possible to exclude each region."""
for region_id in mkt.regions.REGION_IDS:
if region_id == mkt.regions.WORLDWIDE.id:
continue
to_exclude = list(mkt.regions.REGION_IDS)
for region_id in mkt.regions.ALL_REGION_IDS:
to_exclude = list(mkt.regions.ALL_REGION_IDS)
to_exclude.remove(region_id)
form = forms.RegionForm(
data={'regions': to_exclude,
'other_regions': True}, **self.kwargs)
'enable_new_regions': 'on'}, **self.kwargs)
assert form.is_valid(), form.errors
form.save()
eq_(self.app.get_region_ids(False), to_exclude)
eq_(self.app.get_region_ids(True), to_exclude)
def test_brazil_games_excluded(self):
games = Category.objects.create(type=amo.ADDON_WEBAPP, slug='games')
AddonCategory.objects.create(addon=self.app, category=games)
form = forms.RegionForm(data={'regions': mkt.regions.REGION_IDS,
'other_regions': True}, **self.kwargs)
'enable_new_regions': True}, **self.kwargs)
# Developers should still be able to save form OK, even
# if they pass a bad region. Think of the grandfathered developers.
@ -420,7 +241,7 @@ class TestRegionForm(amo.tests.WebappTestCase):
eq_(set(form.initial['regions']),
set(mkt.regions.REGION_IDS) -
set([mkt.regions.BR.id, mkt.regions.WORLDWIDE.id]))
eq_(form.initial['other_regions'], True)
eq_(form.initial['enable_new_regions'], True)
def test_brazil_games_already_excluded(self):
AER.objects.create(addon=self.app, region=mkt.regions.BR.id)
@ -429,7 +250,7 @@ class TestRegionForm(amo.tests.WebappTestCase):
AddonCategory.objects.create(addon=self.app, category=games)
form = forms.RegionForm(data={'regions': mkt.regions.REGION_IDS,
'other_regions': True}, **self.kwargs)
'enable_new_regions': True}, **self.kwargs)
assert form.is_valid()
form.save()
@ -438,7 +259,7 @@ class TestRegionForm(amo.tests.WebappTestCase):
eq_(set(form.initial['regions']),
set(mkt.regions.REGION_IDS) -
set([mkt.regions.BR.id, mkt.regions.WORLDWIDE.id]))
eq_(form.initial['other_regions'], True)
eq_(form.initial['enable_new_regions'], True)
def test_brazil_games_with_content_rating(self):
# This game has a government content rating!
@ -449,8 +270,8 @@ class TestRegionForm(amo.tests.WebappTestCase):
games = Category.objects.create(type=amo.ADDON_WEBAPP, slug='games')
AddonCategory.objects.create(addon=self.app, category=games)
form = forms.RegionForm(data={'regions': mkt.regions.REGION_IDS,
'other_regions': 'on'}, **self.kwargs)
form = forms.RegionForm(data={'regions': mkt.regions.ALL_REGION_IDS,
'enable_new_regions': 'on'}, **self.kwargs)
assert form.is_valid(), form.errors
form.save()
@ -458,7 +279,7 @@ class TestRegionForm(amo.tests.WebappTestCase):
def test_exclude_worldwide(self):
form = forms.RegionForm(data={'regions': mkt.regions.REGION_IDS,
'other_regions': False}, **self.kwargs)
'enable_new_regions': False}, **self.kwargs)
assert form.is_valid(), form.errors
form.save()
eq_(self.app.get_region_ids(True), mkt.regions.REGION_IDS)
@ -466,8 +287,8 @@ class TestRegionForm(amo.tests.WebappTestCase):
def test_reinclude_region(self):
AER.objects.create(addon=self.app, region=mkt.regions.BR.id)
form = forms.RegionForm(data={'regions': mkt.regions.REGION_IDS,
'other_regions': True}, **self.kwargs)
form = forms.RegionForm(data={'regions': mkt.regions.ALL_REGION_IDS,
'enable_new_regions': True}, **self.kwargs)
assert form.is_valid(), form.errors
form.save()
eq_(self.app.get_region_ids(True), mkt.regions.ALL_REGION_IDS)
@ -475,42 +296,22 @@ class TestRegionForm(amo.tests.WebappTestCase):
def test_reinclude_worldwide(self):
AER.objects.create(addon=self.app, region=mkt.regions.WORLDWIDE.id)
form = forms.RegionForm(data={'regions': mkt.regions.REGION_IDS,
'other_regions': True}, **self.kwargs)
form = forms.RegionForm(data={'regions': mkt.regions.ALL_REGION_IDS},
**self.kwargs)
assert form.is_valid(), form.errors
form.save()
eq_(self.app.get_region_ids(True), mkt.regions.ALL_REGION_IDS)
@mock.patch('mkt.developers.forms.ALL_PAID_REGION_IDS',
new=[2, 4, 5, 7])
def test_enable_other_region_paid(self):
def test_worldwide_valid_choice_paid(self):
self.app.update(premium_type=amo.ADDON_PREMIUM)
form = forms.RegionForm(data={'regions': [2, 4],
'other_regions': 'on'}, **self.kwargs)
form.price_region_ids = [2, 4, 7]
# Update disabled_regions as we tweaked price_regions.
form.disabled_regions = form._disabled_regions()
eq_(self.app.enable_new_regions, False)
form = forms.RegionForm(
data={'regions': [mkt.regions.WORLDWIDE.id]}, **self.kwargs)
assert form.is_valid(), form.errors
form.save()
eq_(self.app.enable_new_regions, True)
eq_(self.app.addonexcludedregion.filter(
region=mkt.regions.WORLDWIDE.id).exists(), False)
def test_worldwide_invalid_choice_paid(self):
self.app.update(premium_type=amo.ADDON_PREMIUM)
def test_worldwide_valid_choice_free(self):
form = forms.RegionForm(
data={'regions': [mkt.regions.WORLDWIDE.id]}, **self.kwargs)
assert not form.is_valid(), form.errors
assert ('Select a valid choice. 1 is not one of the available '
'choices.' in form.errors['regions'])
def test_worldwide_invalid_choice(self):
form = forms.RegionForm(
data={'regions': [mkt.regions.WORLDWIDE.id]}, **self.kwargs)
assert not form.is_valid(), form.errors
assert ('Select a valid choice. 1 is not one of the available '
'choices.' in form.errors['regions'])
assert form.is_valid(), form.errors
class TestNewManifestForm(amo.tests.TestCase):

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

@ -225,9 +225,8 @@ class TestPremiumForm(amo.tests.TestCase):
# 1 x Free with inapp
# + 1 x price tier 0
# + 3 x values grouped by billing
# + 1 x 'Please select'
# = 6
eq_(len(form.fields['price'].choices), 6)
# = 5
eq_(len(form.fields['price'].choices), 5)
html = form.as_p()
eq_(len(pq(html)('#id_price optgroup')), 3, 'Should be 3 optgroups')

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

@ -1,97 +0,0 @@
from StringIO import StringIO
from django.core.management import call_command
from django.core.management.base import CommandError
from nose.tools import eq_, ok_, raises
from mock import patch
import amo
import amo.tests
from market.models import AddonPremium, Price
from mkt.developers.management.commands import (
check_paid_app_regions)
from mkt.regions import (ALL_REGION_IDS, REGIONS_CHOICES_ID_DICT,
PL, US, WORLDWIDE)
from mkt.site.fixtures import fixture
from mkt.webapps.models import AddonExcludedRegion as AER, Webapp
class TestRegionManagmentCommand(amo.tests.TestCase):
fixtures = fixture('webapp_337141', 'prices')
@raises(CommandError)
def test_unknown_slug(self):
check_paid_app_regions.Command().handle('whatever')
@patch('mkt.developers.forms.ALL_PAID_REGION_IDS', new=[PL.id, US.id])
@patch('sys.stdout', new_callable=StringIO)
def test_app_has_bad_regions(self, mock_stdout):
app = Webapp.objects.get(id=337141)
app.update(premium_type=amo.ADDON_PREMIUM)
price = Price.objects.get(id=1)
AddonPremium.objects.create(addon=app, price=price)
call_command('check_paid_app_regions', app.app_slug)
# From the fixture poland is the only ok region
# for the price.
stdout_val = mock_stdout.getvalue()
assert 'Poland *' not in stdout_val
assert '* Inappropriate region' in stdout_val
for region_id in ALL_REGION_IDS:
region_id = int(region_id)
if region_id in (PL.id, US.id):
continue
region_name = unicode(REGIONS_CHOICES_ID_DICT.get(
region_id).name)
ok_('%s *' % region_name in stdout_val,
'%s not present' % region_name)
@raises(CommandError)
def test_premium_no_price(self):
app = Webapp.objects.get(id=337141)
app.update(premium_type=amo.ADDON_PREMIUM)
check_paid_app_regions.Command().handle(app.app_slug)
@patch('sys.stdout', new_callable=StringIO)
def test_include_region_by_id(self, mock_stdout):
app = Webapp.objects.get(id=337141)
app.update(premium_type=amo.ADDON_PREMIUM)
price = Price.objects.get(id=1)
AddonPremium.objects.create(addon=app, price=price)
AER.objects.create(addon=app, region=WORLDWIDE.id)
eq_(len(AER.objects.all()), 1)
call_command('check_paid_app_regions', app.app_slug,
include_region_id=WORLDWIDE.id)
eq_(AER.objects.all().exists(), False)
@patch('sys.stdout', new_callable=StringIO)
def test_exclude_region_by_id(self, mock_stdout):
app = Webapp.objects.get(id=337141)
app.update(premium_type=amo.ADDON_PREMIUM)
price = Price.objects.get(id=1)
AddonPremium.objects.create(addon=app, price=price)
eq_(len(AER.objects.all()), 0)
call_command('check_paid_app_regions', app.app_slug,
exclude_region_id=WORLDWIDE.id)
eq_(AER.objects.get(addon=app).region, WORLDWIDE.id)
@patch('sys.stdout', new_callable=StringIO)
@patch('mkt.developers.forms.ALL_PAID_REGION_IDS', new=[PL.id, US.id])
def test_free_with_inapp(self, mock_stdout):
app = Webapp.objects.get(id=337141)
app.update(premium_type=amo.ADDON_FREE_INAPP)
call_command('check_paid_app_regions', app.app_slug)
# From the fixture poland is the only ok region
# for the price.
stdout_val = mock_stdout.getvalue()
assert 'Poland *' not in stdout_val
assert 'United States *' not in stdout_val
assert '* Inappropriate region' in stdout_val
@raises(CommandError)
def test_free_app(self):
app = Webapp.objects.get(id=337141)
app.update(premium_type=amo.ADDON_FREE)
eq_(app.premium_type, amo.ADDON_FREE)
check_paid_app_regions.Command().handle(app.app_slug)

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

@ -17,7 +17,7 @@ from constants.payments import (PAYMENT_METHOD_ALL,
PAYMENT_METHOD_CARD,
PAYMENT_METHOD_OPERATOR)
from mkt.constants.payments import ACCESS_PURCHASE, ACCESS_SIMULATE
from mkt.constants.regions import ALL_PAID_REGION_IDS
from mkt.constants.regions import ALL_REGION_IDS
from market.models import Price
from users.models import UserProfile
@ -254,8 +254,6 @@ class TestPayments(amo.tests.TestCase):
self.price = Price.objects.filter()[0]
self.patch = mock.patch('mkt.developers.models.client')
self.sol = self.patch.start()
prs = set([p['region'] for p in self.price.prices()])
self.price_regions = (set(ALL_PAID_REGION_IDS).intersection(prs))
def tearDown(self):
self.patch.stop()
@ -275,16 +273,6 @@ class TestPayments(amo.tests.TestCase):
base.update(extension)
return base
@mock.patch('mkt.developers.forms.ALL_PAID_REGION_IDS', new=[11])
def test_paid_app_has_correct_regions_when_loaded(self):
self.webapp.update(premium_type=amo.ADDON_PREMIUM)
price = Price.objects.get(pk=1)
res = self.client.post(
self.url, self.get_postdata({'allow_inapp': False,
'price': price.pk}), follow=True)
pqr = pq(res.content)
eq_(len(pqr('input[type=checkbox][value=11]:not(:disabled)')), 1)
def test_free(self):
res = self.client.post(
self.url, self.get_postdata({'toggle-paid': 'free'}), follow=True)
@ -353,7 +341,7 @@ class TestPayments(amo.tests.TestCase):
self.client.post(
self.url, self.get_postdata({'price': 'free',
'allow_inapp': 'True',
'regions': ALL_PAID_REGION_IDS}),
'regions': ALL_REGION_IDS}),
follow=True)
eq_(self.get_webapp().upsold, None)
eq_(AddonPremium.objects.all().count(), 0)
@ -366,7 +354,7 @@ class TestPayments(amo.tests.TestCase):
res = self.client.post(
self.url, self.get_postdata({'allow_inapp': True,
'price': self.price.pk,
'regions': self.price_regions}))
'regions': ALL_REGION_IDS}))
self.assert3xx(res, self.url)
eq_(self.get_webapp().premium_type, amo.ADDON_PREMIUM_INAPP)
@ -419,11 +407,11 @@ class TestPayments(amo.tests.TestCase):
self.client.post(
self.url, self.get_postdata({'price': 'free',
'allow_inapp': 'True',
'regions': self.price_regions}))
'regions': ALL_REGION_IDS}))
eq_(self.get_webapp().premium_type, amo.ADDON_FREE_INAPP)
self.client.post(
self.url, self.get_postdata({'toggle-paid': 'free',
'regions': self.price_regions}))
'regions': ALL_REGION_IDS}))
eq_(self.get_webapp().premium_type, amo.ADDON_FREE)
def test_free_with_inapp_without_account_is_incomplete(self):
@ -434,7 +422,7 @@ class TestPayments(amo.tests.TestCase):
res = self.client.post(
self.url, self.get_postdata({'price': 'free',
'allow_inapp': 'True',
'regions': ALL_PAID_REGION_IDS}))
'regions': ALL_REGION_IDS}))
self.assert3xx(res, self.url)
eq_(self.get_webapp().status, amo.STATUS_NULL)
eq_(AddonPremium.objects.all().count(), 0)
@ -447,7 +435,7 @@ class TestPayments(amo.tests.TestCase):
res = self.client.post(
self.url, self.get_postdata({'price': self.price.pk,
'allow_inapp': 'False',
'regions': self.price_regions}))
'regions': ALL_REGION_IDS}))
self.assert3xx(res, self.url)
eq_(self.get_webapp().status, amo.STATUS_NULL)
@ -494,7 +482,7 @@ class TestPayments(amo.tests.TestCase):
res = self.client.post(
self.url, self.get_postdata({'price': 'free',
'allow_inapp': 'True',
'regions': ALL_PAID_REGION_IDS,
'regions': ALL_REGION_IDS,
'accounts': acct.pk}), follow=True)
self.assertNoFormErrors(res)
eq_(res.status_code, 200)
@ -510,7 +498,7 @@ class TestPayments(amo.tests.TestCase):
res = self.client.post(
self.url, self.get_postdata({'price': self.price.pk,
'accounts': acct.pk,
'regions': self.price_regions}),
'regions': ALL_REGION_IDS}),
follow=True)
eq_(api.bango.premium.post.call_count, 1)
self.assertNoFormErrors(res)
@ -551,7 +539,7 @@ class TestPayments(amo.tests.TestCase):
res = self.client.post(
self.url, self.get_postdata({'accounts': acct.pk,
'price': self.price.pk,
'regions': self.price_regions}),
'regions': ALL_REGION_IDS}),
follow=True)
self.assertFormError(res, 'bango_account_list_form', 'accounts',
[u'You are not permitted to change payment '
@ -575,7 +563,7 @@ class TestPayments(amo.tests.TestCase):
res = self.client.post(
self.url, self.get_postdata({'accounts': owner_acct.pk,
'price': self.price.pk,
'regions': self.price_regions}),
'regions': ALL_REGION_IDS}),
follow=True)
assert (AddonPaymentAccount.objects
.filter(addon=self.webapp).exists())
@ -589,7 +577,7 @@ class TestPayments(amo.tests.TestCase):
res = self.client.post(
self.url, self.get_postdata({'accounts': admin_acct.pk,
'price': self.price.pk,
'regions': self.price_regions}),
'regions': ALL_REGION_IDS}),
follow=True)
self.assertFormError(res, 'bango_account_list_form', 'accounts',
@ -605,7 +593,7 @@ class TestPayments(amo.tests.TestCase):
res = self.client.post(
self.url, self.get_postdata({'accounts': owner_acct.pk,
'price': self.price.pk,
'regions': self.price_regions}),
'regions': ALL_REGION_IDS}),
follow=True)
assert (AddonPaymentAccount.objects
.filter(addon=self.webapp).exists())
@ -628,7 +616,7 @@ class TestPayments(amo.tests.TestCase):
res = self.client.post(
self.url, self.get_postdata({'accounts': owner_acct2.pk,
'price': self.price.pk,
'regions': self.price_regions}),
'regions': ALL_REGION_IDS}),
follow=True)
eq_(res.status_code, 200)
self.assertNoFormErrors(res)
@ -647,7 +635,7 @@ class TestPayments(amo.tests.TestCase):
res = self.client.post(
self.url, self.get_postdata({'accounts': acct.pk,
'price': self.price.pk,
'regions': self.price_regions}),
'regions': ALL_REGION_IDS}),
follow=True)
amo.set_user(self.other)
# Make this user a dev so they have access to the payments page.
@ -676,7 +664,7 @@ class TestPayments(amo.tests.TestCase):
res = self.client.post(self.url,
self.get_postdata({'accounts': owner_acct.pk,
'price': self.price.pk,
'regions': self.price_regions}),
'regions': ALL_REGION_IDS}),
follow=True)
self.assertNoFormErrors(res)
# Login as admin.
@ -792,7 +780,7 @@ class TestRegions(amo.tests.TestCase):
return Addon.objects.get(pk=337141)
def get_dict(self, **kwargs):
extension = {'regions': mkt.regions.REGION_IDS,
extension = {'regions': mkt.regions.ALL_REGION_IDS,
'other_regions': 'on',
'free_platforms': ['free-%s' % dt.class_name for dt in
self.webapp.device_types]}
@ -803,7 +791,7 @@ class TestRegions(amo.tests.TestCase):
return sorted(AER.objects.filter(addon=self.webapp)
.values_list('region', flat=True))
def test_edit_other_categories_are_not_excluded(self):
def test_edit_all_regions_are_not_excluded(self):
# Keep the category around for good measure.
Category.objects.create(type=amo.ADDON_WEBAPP, slug='games')
@ -819,7 +807,7 @@ class TestRegions(amo.tests.TestCase):
self.assertNoFormErrors(r)
td = pq(r.content)('#regions')
eq_(td.find('div[data-disabled]').attr('data-disabled'),
eq_(td.find('div[data-disabled-regions]').attr('data-disabled-regions'),
'[%d]' % mkt.regions.BR.id)
eq_(td.find('.note.disabled-regions').length, 1)
@ -833,13 +821,13 @@ class TestRegions(amo.tests.TestCase):
r = self.client.get(self.url)
td = pq(r.content)('#regions')
eq_(td.find('div[data-disabled]').attr('data-disabled'), '[]')
eq_(td.find('div[data-disabled-regions]').attr('data-disabled-regions'), '[]')
eq_(td.find('.note.disabled-regions').length, 0)
def test_brazil_other_cats_form_enabled(self):
r = self.client.get(self.url)
td = pq(r.content)('#regions')
eq_(td.find('div[data-disabled]').attr('data-disabled'), '[]')
eq_(td.find('div[data-disabled-regions]').attr('data-disabled-regions'), '[]')
eq_(td.find('.note.disabled-regions').length, 0)

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

@ -32,6 +32,7 @@ from mkt.constants import DEVICE_LOOKUP
from mkt.developers.decorators import dev_required
from mkt.developers.models import (AddonPaymentAccount, PaymentAccount,
UserInappKey, uri_to_pk)
from mkt.regions import ALL_PAID_REGION_IDS_BY_SLUG
from . import forms, forms_payments
@ -62,10 +63,6 @@ def payments(request, addon_id, addon, webapp=False):
request.POST or None, addon=addon, user=request.amo_user)
if request.method == 'POST':
if premium_form.is_valid():
region_form = forms.RegionForm(request.POST, product=addon,
request=request, price=premium_form.cleaned_data['price']
)
success = all(form.is_valid() for form in
[premium_form, region_form, upsell_form,
@ -146,7 +143,9 @@ def payments(request, addon_id, addon, webapp=False):
PAYMENT_METHOD_ALL: _('All'),
PAYMENT_METHOD_CARD: _('Credit card'),
PAYMENT_METHOD_OPERATOR: _('Carrier'),
}})
},
'all_paid_region_ids_by_slug': ALL_PAID_REGION_IDS_BY_SLUG,
})
@login_required

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

@ -577,13 +577,6 @@ class Webapp(Addon):
return sorted(list(excluded))
def get_possible_price_region_ids(self):
# TODO: Stuart is going to rip this out.
if self.has_premium() and self.premium:
ids = [p['region'] for p in self.premium.price.prices()]
return sorted(ids)
return []
def get_price_region_ids(self):
tier = self.get_tier()
if tier:

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

@ -232,21 +232,6 @@ class TestWebapp(amo.tests.TestCase):
webapp._premium.price = 0
eq_(webapp.has_premium(), True)
def test_get_possible_prices_premium(self):
webapp = Webapp.objects.create(premium_type=amo.ADDON_PREMIUM)
price = Price.objects.get(pk=1)
AddonPremium.objects.create(addon=webapp, price=price)
ok_(len(webapp.get_possible_price_region_ids()) > 0)
ok_(isinstance(webapp.get_possible_price_region_ids(), list))
def test_get_possible_prices_premium_then_free_inapp(self):
webapp = Webapp.objects.create(premium_type=amo.ADDON_PREMIUM)
price = Price.objects.get(pk=1)
AddonPremium.objects.create(addon=webapp, price=price)
webapp.premium_type = amo.ADDON_FREE_INAPP
eq_(len(webapp.get_possible_price_region_ids()), 0)
ok_(isinstance(webapp.get_possible_price_region_ids(), list))
def test_get_price_no_premium(self):
webapp = Webapp(premium_type=amo.ADDON_PREMIUM)
eq_(webapp.get_price(), None)