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
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]});
......
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