Merge pull request #10349 from edx/multi-tenancy/update-receipt-page
Updated receipt page to use order endpoint
This commit is contained in:
@@ -7,7 +7,7 @@ from commerce.api.v0 import views
|
||||
BASKET_URLS = patterns(
|
||||
'',
|
||||
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(
|
||||
|
||||
@@ -7,13 +7,19 @@ import ddt
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.test import TestCase
|
||||
from django.test.utils import override_settings
|
||||
from edx_rest_api_client import exceptions
|
||||
from flaky import flaky
|
||||
from nose.plugins.attrib import attr
|
||||
import pytz
|
||||
from rest_framework.utils.encoders import JSONEncoder
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
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 student.tests.factories import UserFactory
|
||||
from verify_student.models import VerificationDeadline
|
||||
@@ -307,3 +313,38 @@ class CourseRetrieveUpdateViewTests(CourseApiViewTestMixin, ModuleStoreTestCase)
|
||||
]
|
||||
}
|
||||
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
|
||||
|
||||
from commerce.api.v1 import views
|
||||
|
||||
|
||||
COURSE_URLS = patterns(
|
||||
'',
|
||||
url(r'^$', views.CourseListView.as_view(), name='list'),
|
||||
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(
|
||||
'',
|
||||
url(r'^courses/', include(COURSE_URLS, namespace='courses')),
|
||||
|
||||
url(r'^orders/', include(ORDER_URLS, namespace='orders')),
|
||||
)
|
||||
|
||||
@@ -2,16 +2,20 @@
|
||||
import logging
|
||||
|
||||
from django.http import Http404
|
||||
from edx_rest_api_client import exceptions
|
||||
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.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.permissions import ApiKeyOrModelPermission
|
||||
from commerce.api.v1.serializers import CourseSerializer
|
||||
from course_modes.models import CourseMode
|
||||
from openedx.core.lib.api.mixins import PutAsCreateMixin
|
||||
from util.json_request import JsonResponse
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -54,3 +58,18 @@ class CourseRetrieveUpdateView(PutAsCreateMixin, RetrieveUpdateAPIView):
|
||||
# There is nothing to pre-save. The default behavior changes the Course.id attribute from
|
||||
# a CourseKey to a string, which is not desired.
|
||||
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
|
||||
|
||||
def get_uri(self):
|
||||
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 || {};
|
||||
|
||||
edx.commerce.ReceiptView = Backbone.View.extend({
|
||||
useEcommerceApi: true,
|
||||
ecommerceBasketId: null,
|
||||
ecommerceOrderNumber: null,
|
||||
|
||||
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');
|
||||
|
||||
/* Mix non-conflicting functions from underscore.string (all but include, contains, and reverse) into
|
||||
@@ -75,7 +79,7 @@ var edx = edx || {};
|
||||
|
||||
render: function () {
|
||||
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') {
|
||||
// Get the order details
|
||||
@@ -106,14 +110,21 @@ var edx = edx || {};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
getReceiptData: function (basketId) {
|
||||
var urlFormat = this.useEcommerceApi ? '/api/commerce/v0/baskets/%s/order/' : '/shoppingcart/receipt/%s/';
|
||||
getReceiptData: function (orderId) {
|
||||
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({
|
||||
url: _.sprintf(urlFormat, basketId),
|
||||
url: _.sprintf(urlFormat, orderId),
|
||||
type: 'GET',
|
||||
dataType: 'json'
|
||||
}).retry({times: 5, timeout: 2000, statusCodes: [404]});
|
||||
|
||||
Reference in New Issue
Block a user