Skip to content
This repository was archived by the owner on Jan 25, 2018. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions lib/solitude/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ def configure_product_for_billing(self, transaction_uuid,
redirect_url_onsuccess,
redirect_url_onerror,
prices, icon_url,
user_uuid):
user_uuid, application_size):
"""
Get the billing configuration ID for a Bango transaction.
"""
Expand All @@ -192,8 +192,8 @@ def configure_product_for_billing(self, transaction_uuid,
seller_product__seller=seller_id,
seller_product__external_id=product_id)['resource_uri']
except ObjectDoesNotExist:
bango_product_uri = self.create_product(product_id,
product_name, seller)
bango_product_uri = self.create_product(product_id, product_name,
seller)

log.info('transaction %s: bango product: %s'
% (transaction_uuid, bango_product_uri))
Expand All @@ -206,7 +206,8 @@ def configure_product_for_billing(self, transaction_uuid,
'redirect_url_onsuccess': redirect_url_onsuccess,
'redirect_url_onerror': redirect_url_onerror,
'icon_url': icon_url,
'user_uuid': user_uuid
'user_uuid': user_uuid,
'application_size': application_size
})
bill_id = res['billingConfigurationId']
log.info('transaction %s: billing config ID: %s; '
Expand Down
6 changes: 3 additions & 3 deletions lib/solitude/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,23 +206,23 @@ def test_create_bango(self, slumber):
def test_no_seller(self, slumber):
slumber.generic.seller.get_object.side_effect = ObjectDoesNotExist
with self.assertRaises(SellerNotConfigured):
client.configure_product_for_billing(*range(0, 9))
client.configure_product_for_billing(*range(0, 10))

@mock.patch('lib.solitude.api.client.slumber')
def test_no_bango(self, slumber):
slumber.generic.seller.get_object.return_value = self.seller
slumber.bango.billing.post.return_value = {
'billingConfigurationId': 'bar'}
slumber.bango.product.get_object.side_effect = ObjectDoesNotExist
eq_(client.configure_product_for_billing(*range(0, 9)), ('bar', 'foo'))
eq_(client.configure_product_for_billing(*range(0, 10)), ('bar', 'foo'))

@mock.patch('lib.solitude.api.client.slumber')
def test_has_bango(self, slumber):
slumber.generic.seller.get_object.return_value = self.seller
slumber.bango.billing.post.return_value = {
'billingConfigurationId': 'bar'}
slumber.bango.product.get_object.return_value = {'resource_uri': 'foo'}
eq_(client.configure_product_for_billing(*range(0, 9)), ('bar', 'foo'))
eq_(client.configure_product_for_billing(*range(0, 10)), ('bar', 'foo'))


@mock.patch('lib.solitude.api.client.slumber')
Expand Down
14 changes: 10 additions & 4 deletions webpay/pay/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def get_seller_uuid(issuer_key, product_data):
# actual Solitude/Bango seller_uuid to associate the
# product to the right account.
try:
seller_uuid = urlparse.parse_qs(product_data)['seller_uuid'][0]
seller_uuid = product_data['seller_uuid'][0]
except KeyError:
raise ValueError('Marketplace %r did not put a seller_uuid '
'in productData: %r'
Expand Down Expand Up @@ -124,9 +124,14 @@ def start_pay(transaction_uuid, notes, user_uuid, **kw):
ready to be fulfilled by Bango.
"""
pay = notes['pay_request']
product_data = urlparse.parse_qs(pay['request'].get('productData', ''))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moving urlparse here means that we'll attempt to parse productData from all 3rd party merchants doing in-app purchases. Some value could theoretically cause an exception here but I tried a lot of different things and could not find a way to raise an exception :) So I suppose this is ok.

try:
seller_uuid = get_seller_uuid(notes['issuer_key'],
pay['request'].get('productData', ''))
seller_uuid = get_seller_uuid(notes['issuer_key'], product_data)
try:
application_size = int(product_data['application_size'][0])
except (KeyError, ValueError):
application_size = None

# Ask the marketplace for a valid price point.
prices = mkt_client.get_price(pay['request']['pricePoint'])
log.debug('pricePoint=%s prices=%s' % (pay['request']['pricePoint'],
Expand All @@ -148,7 +153,8 @@ def start_pay(transaction_uuid, notes, user_uuid, **kw):
absolutify(reverse('bango.error')),
prices['prices'],
icon_url,
user_uuid
user_uuid,
application_size,
)
trans_pk = client.slumber.generic.transaction.get_object(
uuid=transaction_uuid)['resource_pk']
Expand Down
58 changes: 49 additions & 9 deletions webpay/pay/tests/test_tasks.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import calendar
import time
import urllib2
from urllib import urlencode

from django import test
from django.conf import settings
Expand Down Expand Up @@ -405,10 +406,10 @@ def start(self, marketplace, solitude):
prices.get_object.return_value = self.prices
marketplace.webpay.prices.return_value = prices
solitude.get_transaction.return_value = {
'status': constants.STATUS_CANCELLED,
'notes': self.notes,
'type': constants.TYPE_PAYMENT,
'uuid': self.transaction_uuid
'status': constants.STATUS_CANCELLED,
'notes': self.notes,
'type': constants.TYPE_PAYMENT,
'uuid': self.transaction_uuid
}
tasks.start_pay(self.transaction_uuid, self.notes, self.user_uuid)

Expand Down Expand Up @@ -505,7 +506,7 @@ def test_marketplace_seller_switch(self, marketplace, solitude):
# Simulate how the Marketplace would add
# a custom seller_uuid to the product data in the JWT.
app_seller_uuid = 'some-seller-uuid'
data = 'seller_uuid=%s' % app_seller_uuid
data = urlencode({'seller_uuid': app_seller_uuid})
self.notes['issuer_key'] = 'marketplace-domain'
self.notes['pay_request']['request']['productData'] = data
self.start()
Expand All @@ -514,6 +515,45 @@ def test_marketplace_seller_switch(self, marketplace, solitude):
solitude.generic.seller.get_object.assert_called_with(
uuid=app_seller_uuid)

@mock.patch.object(settings, 'KEY', 'marketplace-domain')
@mock.patch('lib.solitude.api.client.slumber')
def test_marketplace_application_size(self, solitude):
# Simulate how the Marketplace would add
# a custom seller_uuid and application_size
# to the product data in the JWT.
app_seller_uuid = 'some-seller-uuid'
application_size = 10
data = urlencode({
'seller_uuid': app_seller_uuid,
'application_size': application_size})
self.notes['issuer_key'] = 'marketplace-domain'
self.notes['pay_request']['request']['productData'] = data
solitude.bango.product.get_object.side_effect = ObjectDoesNotExist
self.start()

# Check that the application size is the one submitted in productData.
eq_(solitude.bango.billing.post.call_args[0][0]['application_size'],
application_size)


@mock.patch.object(settings, 'KEY', 'marketplace-domain')
@mock.patch('lib.solitude.api.client.slumber')
def test_marketplace_wrong_application_size(self, solitude):
app_seller_uuid = 'some-seller-uuid'
application_size = 'foo'
data = urlencode({
'seller_uuid': app_seller_uuid,
'application_size': application_size})
self.notes['issuer_key'] = 'marketplace-domain'
self.notes['pay_request']['request']['productData'] = data
solitude.bango.product.get_object.side_effect = ObjectDoesNotExist
self.start()

# Check that the application size fallbacks to None if invalid.
eq_(solitude.bango.billing.post.call_args[0][0]['application_size'],
None)


@raises(ValueError)
@mock.patch.object(settings, 'KEY', 'marketplace-domain')
@mock.patch('lib.solitude.api.client.api')
Expand All @@ -533,10 +573,10 @@ def start(self, marketplace, solitude):
prices.get_object.return_value = self.prices
marketplace.webpay.prices.return_value = prices
solitude.get_transaction.return_value = {
'status': constants.STATUS_CANCELLED,
'notes': self.notes,
'type': constants.TYPE_PAYMENT,
'uuid': self.transaction_uuid
'status': constants.STATUS_CANCELLED,
'notes': self.notes,
'type': constants.TYPE_PAYMENT,
'uuid': self.transaction_uuid
}
request = RequestFactory().get('/')
request.session = {}
Expand Down