Commit 0fece869 by Clinton Blackburn

Merge pull request #10349 from edx/multi-tenancy/update-receipt-page

Updated receipt page to use order endpoint
parents de7113a1 9bb3f703
...@@ -7,7 +7,7 @@ from commerce.api.v0 import views ...@@ -7,7 +7,7 @@ from commerce.api.v0 import views
BASKET_URLS = patterns( BASKET_URLS = patterns(
'', '',
url(r'^$', views.BasketsView.as_view(), name='create'), url(r'^$', views.BasketsView.as_view(), name='create'),
url(r'^{}/order/$'.format(r'(?P<basket_id>[\w]+)'), views.BasketOrderView.as_view(), name='retrieve_order'), url(r'^(?P<basket_id>[\w]+)/order/$', views.BasketOrderView.as_view(), name='retrieve_order'),
) )
urlpatterns = patterns( urlpatterns = patterns(
......
...@@ -7,13 +7,19 @@ import ddt ...@@ -7,13 +7,19 @@ import ddt
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.test import TestCase
from django.test.utils import override_settings from django.test.utils import override_settings
from edx_rest_api_client import exceptions
from flaky import flaky from flaky import flaky
from nose.plugins.attrib import attr
import pytz import pytz
from rest_framework.utils.encoders import JSONEncoder from rest_framework.utils.encoders import JSONEncoder
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory from xmodule.modulestore.tests.factories import CourseFactory
from commerce.tests import TEST_API_URL, TEST_API_SIGNING_KEY
from commerce.tests.mocks import mock_order_endpoint
from commerce.tests.test_views import UserMixin
from course_modes.models import CourseMode from course_modes.models import CourseMode
from student.tests.factories import UserFactory from student.tests.factories import UserFactory
from verify_student.models import VerificationDeadline from verify_student.models import VerificationDeadline
...@@ -307,3 +313,38 @@ class CourseRetrieveUpdateViewTests(CourseApiViewTestMixin, ModuleStoreTestCase) ...@@ -307,3 +313,38 @@ class CourseRetrieveUpdateViewTests(CourseApiViewTestMixin, ModuleStoreTestCase)
] ]
} }
self.assertDictEqual(expected_dict, json.loads(response.content)) self.assertDictEqual(expected_dict, json.loads(response.content))
@attr('shard_1')
@override_settings(ECOMMERCE_API_URL=TEST_API_URL, ECOMMERCE_API_SIGNING_KEY=TEST_API_SIGNING_KEY)
class OrderViewTests(UserMixin, TestCase):
""" Tests for the basket order view. """
view_name = 'commerce_api:v1:orders:detail'
ORDER_NUMBER = 'EDX-100001'
MOCK_ORDER = {'number': ORDER_NUMBER}
path = reverse(view_name, kwargs={'number': ORDER_NUMBER})
def setUp(self):
super(OrderViewTests, self).setUp()
self._login()
def test_order_found(self):
""" If the order is located, the view should pass the data from the API. """
with mock_order_endpoint(order_number=self.ORDER_NUMBER, response=self.MOCK_ORDER):
response = self.client.get(self.path)
self.assertEqual(response.status_code, 200)
actual = json.loads(response.content)
self.assertEqual(actual, self.MOCK_ORDER)
def test_order_not_found(self):
""" If the order is not found, the view should return a 404. """
with mock_order_endpoint(order_number=self.ORDER_NUMBER, exception=exceptions.HttpNotFoundError):
response = self.client.get(self.path)
self.assertEqual(response.status_code, 404)
def test_login_required(self):
""" The view should return 403 if the user is not logged in. """
self.client.logout()
response = self.client.get(self.path)
self.assertEqual(response.status_code, 403)
...@@ -4,15 +4,19 @@ from django.conf.urls import patterns, url, include ...@@ -4,15 +4,19 @@ from django.conf.urls import patterns, url, include
from commerce.api.v1 import views from commerce.api.v1 import views
COURSE_URLS = patterns( COURSE_URLS = patterns(
'', '',
url(r'^$', views.CourseListView.as_view(), name='list'), url(r'^$', views.CourseListView.as_view(), name='list'),
url(r'^{}/$'.format(settings.COURSE_ID_PATTERN), views.CourseRetrieveUpdateView.as_view(), name='retrieve_update'), url(r'^{}/$'.format(settings.COURSE_ID_PATTERN), views.CourseRetrieveUpdateView.as_view(), name='retrieve_update'),
) )
ORDER_URLS = patterns(
'',
url(r'^(?P<number>[-\w]+)/$', views.OrderView.as_view(), name='detail'),
)
urlpatterns = patterns( urlpatterns = patterns(
'', '',
url(r'^courses/', include(COURSE_URLS, namespace='courses')), url(r'^courses/', include(COURSE_URLS, namespace='courses')),
url(r'^orders/', include(ORDER_URLS, namespace='orders')),
) )
...@@ -2,16 +2,20 @@ ...@@ -2,16 +2,20 @@
import logging import logging
from django.http import Http404 from django.http import Http404
from edx_rest_api_client import exceptions
from rest_framework.authentication import SessionAuthentication from rest_framework.authentication import SessionAuthentication
from rest_framework_oauth.authentication import OAuth2Authentication from rest_framework.views import APIView
from rest_framework.generics import RetrieveUpdateAPIView, ListAPIView from rest_framework.generics import RetrieveUpdateAPIView, ListAPIView
from rest_framework.permissions import IsAuthenticated from rest_framework.permissions import IsAuthenticated
from rest_framework_oauth.authentication import OAuth2Authentication
from commerce import ecommerce_api_client
from commerce.api.v1.models import Course from commerce.api.v1.models import Course
from commerce.api.v1.permissions import ApiKeyOrModelPermission from commerce.api.v1.permissions import ApiKeyOrModelPermission
from commerce.api.v1.serializers import CourseSerializer from commerce.api.v1.serializers import CourseSerializer
from course_modes.models import CourseMode from course_modes.models import CourseMode
from openedx.core.lib.api.mixins import PutAsCreateMixin from openedx.core.lib.api.mixins import PutAsCreateMixin
from util.json_request import JsonResponse
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -54,3 +58,18 @@ class CourseRetrieveUpdateView(PutAsCreateMixin, RetrieveUpdateAPIView): ...@@ -54,3 +58,18 @@ class CourseRetrieveUpdateView(PutAsCreateMixin, RetrieveUpdateAPIView):
# There is nothing to pre-save. The default behavior changes the Course.id attribute from # There is nothing to pre-save. The default behavior changes the Course.id attribute from
# a CourseKey to a string, which is not desired. # a CourseKey to a string, which is not desired.
pass pass
class OrderView(APIView):
""" Retrieve order details. """
authentication_classes = (SessionAuthentication,)
permission_classes = (IsAuthenticated,)
def get(self, request, number): # pylint:disable=unused-argument
""" HTTP handler. """
try:
order = ecommerce_api_client(request.user).orders(number).get()
return JsonResponse(order)
except exceptions.HttpNotFoundError:
return JsonResponse(status=404)
...@@ -103,3 +103,17 @@ class mock_create_refund(mock_ecommerce_api_endpoint): # pylint: disable=invali ...@@ -103,3 +103,17 @@ class mock_create_refund(mock_ecommerce_api_endpoint): # pylint: disable=invali
def get_uri(self): def get_uri(self):
return TEST_API_URL + '/refunds/' return TEST_API_URL + '/refunds/'
class mock_order_endpoint(mock_ecommerce_api_endpoint): # pylint: disable=invalid-name
""" Mocks calls to E-Commerce API client basket order method. """
default_response = {'number': 'EDX-100001'}
method = httpretty.GET
def __init__(self, order_number, **kwargs):
super(mock_order_endpoint, self).__init__(**kwargs)
self.order_number = order_number
def get_uri(self):
return TEST_API_URL + '/orders/{}/'.format(self.order_number)
...@@ -10,9 +10,13 @@ var edx = edx || {}; ...@@ -10,9 +10,13 @@ var edx = edx || {};
edx.commerce.ReceiptView = Backbone.View.extend({ edx.commerce.ReceiptView = Backbone.View.extend({
useEcommerceApi: true, useEcommerceApi: true,
ecommerceBasketId: null,
ecommerceOrderNumber: null,
initialize: function () { initialize: function () {
this.useEcommerceApi = !!($.url('?basket_id')); this.ecommerceBasketId = $.url('?basket_id');
this.ecommerceOrderNumber = $.url('?orderNum');
this.useEcommerceApi = this.ecommerceBasketId || this.ecommerceOrderNumber;
_.bindAll(this, 'renderReceipt', 'renderError', 'getProviderData', 'renderProvider', 'getCourseData'); _.bindAll(this, 'renderReceipt', 'renderError', 'getProviderData', 'renderProvider', 'getCourseData');
/* Mix non-conflicting functions from underscore.string (all but include, contains, and reverse) into /* Mix non-conflicting functions from underscore.string (all but include, contains, and reverse) into
...@@ -75,7 +79,7 @@ var edx = edx || {}; ...@@ -75,7 +79,7 @@ var edx = edx || {};
render: function () { render: function () {
var self = this, var self = this,
orderId = $.url('?basket_id') || $.url('?payment-order-num'); orderId = this.ecommerceOrderNumber || this.ecommerceBasketId || $.url('?payment-order-num');
if (orderId && this.$el.data('is-payment-complete') === 'True') { if (orderId && this.$el.data('is-payment-complete') === 'True') {
// Get the order details // Get the order details
...@@ -106,14 +110,21 @@ var edx = edx || {}; ...@@ -106,14 +110,21 @@ var edx = edx || {};
/** /**
* Retrieve receipt data from Oscar (via LMS). * Retrieve receipt data from Oscar (via LMS).
* @param {int} basketId The basket that was purchased. * @param {string} orderId Identifier of the order that was purchased.
* @return {object} JQuery Promise. * @return {object} JQuery Promise.
*/ */
getReceiptData: function (basketId) { getReceiptData: function (orderId) {
var urlFormat = this.useEcommerceApi ? '/api/commerce/v0/baskets/%s/order/' : '/shoppingcart/receipt/%s/'; var urlFormat = '/shoppingcart/receipt/%s/';
if (this.ecommerceOrderNumber) {
urlFormat = '/api/commerce/v1/orders/%s/';
} else if (this.ecommerceBasketId){
urlFormat = '/api/commerce/v0/baskets/%s/order/';
}
return $.ajax({ return $.ajax({
url: _.sprintf(urlFormat, basketId), url: _.sprintf(urlFormat, orderId),
type: 'GET', type: 'GET',
dataType: 'json' dataType: 'json'
}).retry({times: 5, timeout: 2000, statusCodes: [404]}); }).retry({times: 5, timeout: 2000, statusCodes: [404]});
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment