Ejemplo n.º 1
0
    def test_no_product(self):
        """ Verify that an exception is raised if there is no product. """
        voucher = VoucherFactory(code='NOPRODUCT')
        offer = ConditionalOfferFactory()
        voucher.offers.add(offer)

        with self.assertRaises(exceptions.ProductNotFoundError):
            get_voucher_and_products_from_code(code='NOPRODUCT')
Ejemplo n.º 2
0
    def test_no_product(self):
        """ Verify that an exception is raised if there is no product. """
        voucher = VoucherFactory(code='NOPRODUCT')
        offer = ConditionalOfferFactory()
        voucher.offers.add(offer)

        with self.assertRaises(exceptions.ProductNotFoundError):
            get_voucher_and_products_from_code(code='NOPRODUCT')
Ejemplo n.º 3
0
    def test_get_offers_for_multiple_courses_voucher(self):
        """ Verify that the course offers data is returned for a multiple courses voucher. """
        course, seat = self.create_course_and_seat()
        self.mock_dynamic_catalog_course_runs_api(query='*:*', course_run=course)
        new_range, __ = Range.objects.get_or_create(catalog_query='*:*')
        new_range.add_product(seat)
        voucher, __ = prepare_voucher(_range=new_range, benefit_value=10)
        voucher, products = get_voucher_and_products_from_code(voucher.code)
        benefit = voucher.offers.first().benefit
        request = self.prepare_offers_listing_request(voucher.code)
        offers = VoucherViewSet().get_offers(products=products, request=request, voucher=voucher)
        first_offer = offers[0]

        self.assertEqual(len(offers), 1)
        self.assertDictEqual(first_offer, {
            'benefit': {
                'type': benefit.type,
                'value': benefit.value
            },
            'contains_verified': False,
            'course_start_date': '2016-05-01T00:00:00Z',
            'id': course.id,
            'image_url': 'path/to/the/course/image',
            'organization': CourseKey.from_string(course.id).org,
            'seat_type': course.type,
            'stockrecords': serializers.StockRecordSerializer(seat.stockrecords.first()).data,
            'title': course.name,
            'voucher_end_date': voucher.end_datetime
        })
Ejemplo n.º 4
0
    def offers(self, request):
        """
        Preview the courses offered by the voucher.
        Paginated Response containing the list of course offers will be returned.
        ---
        parameters:
            - name: code
              description: Voucher code
              required: true
              type: string
              paramType: query
              multiple: false
        """
        code = request.GET.get('code', '')

        try:
            voucher, products = get_voucher_and_products_from_code(code)
        except Voucher.DoesNotExist:
            logger.error('Voucher with code %s not found.', code)
            return Response(status=status.HTTP_400_BAD_REQUEST)
        except exceptions.ProductNotFoundError:
            logger.error('No product(s) are associated with this code.')
            return Response(status=status.HTTP_400_BAD_REQUEST)

        offers = self.get_offers(products, request, voucher)
        page = self.paginate_queryset(offers)
        return self.get_paginated_response(page)
Ejemplo n.º 5
0
    def test_get_offers_for_single_course_voucher(self):
        """ Verify that the course offers data is returned for a single course voucher. """
        course, seat = self.create_course_and_seat()
        new_range = RangeFactory(products=[seat, ])
        voucher, __ = prepare_voucher(_range=new_range, benefit_value=10)
        voucher, products = get_voucher_and_products_from_code(voucher.code)
        benefit = voucher.offers.first().benefit
        request = self.prepare_offers_listing_request(voucher.code)
        self.mock_course_api_response(course=course)
        offers = VoucherViewSet().get_offers(products=products, request=request, voucher=voucher)
        first_offer = offers[0]

        self.assertEqual(len(offers), 1)
        self.assertDictEqual(first_offer, {
            'benefit': {
                'type': benefit.type,
                'value': benefit.value
            },
            'contains_verified': True,
            'course_start_date': '2013-02-05T05:00:00Z',
            'id': course.id,
            'image_url': get_lms_url('/asset-v1:test+test+test+type@asset+block@images_course_image.jpg'),
            'organization': CourseKey.from_string(course.id).org,
            'seat_type': course.type,
            'stockrecords': serializers.StockRecordSerializer(seat.stockrecords.first()).data,
            'title': course.name,
            'voucher_end_date': voucher.end_datetime
        })
Ejemplo n.º 6
0
    def offers(self, request):
        """
        Preview the courses offered by the voucher.
        Paginated Response containing the list of course offers will be returned.
        ---
        parameters:
            - name: code
              description: Voucher code
              required: true
              type: string
              paramType: query
              multiple: false
        """
        code = request.GET.get('code', '')

        try:
            voucher, products = get_voucher_and_products_from_code(code)
        except Voucher.DoesNotExist:
            logger.error('Voucher with code %s not found.', code)
            return Response(status=status.HTTP_400_BAD_REQUEST)
        except exceptions.ProductNotFoundError:
            logger.error('No product(s) are associated with this code.')
            return Response(status=status.HTTP_400_BAD_REQUEST)

        offers = self.get_offers(products, request, voucher)
        page = self.paginate_queryset(offers)
        return self.get_paginated_response(page)
Ejemplo n.º 7
0
    def test_get_voucher_and_products_from_code(self):
        """ Verify that get_voucher_and_products_from_code() returns products and voucher. """
        original_voucher, original_product = prepare_voucher(code=COUPON_CODE)
        voucher, products = get_voucher_and_products_from_code(code=COUPON_CODE)

        self.assertIsNotNone(voucher)
        self.assertEqual(voucher, original_voucher)
        self.assertEqual(voucher.code, COUPON_CODE)
        self.assertEqual(len(products), 1)
        self.assertEqual(products[0], original_product)
Ejemplo n.º 8
0
    def test_get_voucher_and_products_from_code(self):
        """ Verify that get_voucher_and_products_from_code() returns products and voucher. """
        original_voucher, original_product = prepare_voucher(code=COUPON_CODE)
        voucher, products = get_voucher_and_products_from_code(code=COUPON_CODE)

        self.assertIsNotNone(voucher)
        self.assertEqual(voucher, original_voucher)
        self.assertEqual(voucher.code, COUPON_CODE)
        self.assertEqual(len(products), 1)
        self.assertEqual(products[0], original_product)
Ejemplo n.º 9
0
    def test_voucher_offers_listing_catalog_query(self):
        """ Verify the endpoint returns offers data for single product range. """
        course, seat = self.create_course_and_seat()
        self.mock_dynamic_catalog_course_runs_api(query='*:*', course_run=course)
        new_range, __ = Range.objects.get_or_create(catalog_query='*:*')
        new_range.add_product(seat)
        voucher, __ = prepare_voucher(_range=new_range)
        voucher, __ = get_voucher_and_products_from_code(voucher.code)
        request = self.prepare_offers_listing_request(voucher.code)
        response = self.endpointView(request)

        self.assertEqual(response.status_code, 200)
        self.assertGreater(len(response.data), 0)
Ejemplo n.º 10
0
    def get(self, request):
        partner = get_partner_for_site(request)

        sku = request.GET.get('sku', None)
        code = request.GET.get('code', None)

        if not sku:
            return HttpResponseBadRequest(_('No SKU provided.'))

        if code:
            voucher, __ = get_voucher_and_products_from_code(code=code)
        else:
            voucher = None

        try:
            product = StockRecord.objects.get(partner=partner,
                                              partner_sku=sku).product
        except StockRecord.DoesNotExist:
            return HttpResponseBadRequest(
                _('SKU [{sku}] does not exist.').format(sku=sku))

        # If the product isn't available then there's no reason to continue with the basket addition
        purchase_info = request.strategy.fetch_for_product(product)
        if not purchase_info.availability.is_available_to_buy:
            msg = _('Product [{product}] not available to buy.').format(
                product=product.title)
            return HttpResponseBadRequest(msg)

        # If the product is not an Enrollment Code, we check to see if the user is already
        # enrolled to prevent double-enrollment and/or accidental coupon usage
        if product.get_product_class(
        ).name != ENROLLMENT_CODE_PRODUCT_CLASS_NAME:
            try:
                if request.user.is_user_already_enrolled(request, product):
                    logger.warning(
                        'User [%s] attempted to repurchase the [%s] seat of course [%s]',
                        request.user.username, mode_for_seat(product),
                        product.attr.course_key)
                    msg = _('You are already enrolled in {course}.').format(
                        course=product.course.name)
                    return HttpResponseBadRequest(msg)
            except (ConnectionError, SlumberBaseException, Timeout):
                msg = _(
                    'An error occurred while retrieving enrollment details. Please try again.'
                )
                return HttpResponseBadRequest(msg)

        # At this point we're either adding an Enrollment Code product to the basket,
        # or the user is adding a Seat product for which they are not already enrolled
        prepare_basket(request, product, voucher)
        return HttpResponseRedirect(reverse('basket:summary'), status=303)
Ejemplo n.º 11
0
    def test_voucher_offers_listing_catalog_query(self):
        """ Verify the endpoint returns offers data for single product range. """
        course, seat = self.create_course_and_seat()
        self.mock_dynamic_catalog_course_runs_api(query='*:*',
                                                  course_run=course)
        new_range, __ = Range.objects.get_or_create(catalog_query='*:*')
        new_range.add_product(seat)
        voucher, __ = prepare_voucher(_range=new_range)
        voucher, __ = get_voucher_and_products_from_code(voucher.code)
        request = self.prepare_offers_listing_request(voucher.code)
        response = self.endpointView(request)

        self.assertEqual(response.status_code, 200)
        self.assertGreater(len(response.data), 0)
Ejemplo n.º 12
0
    def test_omitting_unavailable_seats(self):
        """ Verify an unavailable seat is omitted from offer page results. """
        course1, seat1 = self.create_course_and_seat()
        course2, seat2 = self.create_course_and_seat()
        course_run_info = {
            'count':
            2,
            'next':
            'path/to/the/next/page',
            'results': [{
                'key': course1.id,
                'title': course1.name,
                'start': '2016-05-01T00:00:00Z',
                'image': {
                    'src': 'path/to/the/course/image'
                }
            }, {
                'key': course2.id,
                'title': course2.name,
                'start': '2016-05-01T00:00:00Z',
                'image': {
                    'src': 'path/to/the/course/image'
                }
            }]
        }

        self.mock_dynamic_catalog_course_runs_api(
            query='*:*', course_run_info=course_run_info)
        new_range, __ = Range.objects.get_or_create(catalog_query='*:*')
        new_range.add_product(seat1)
        new_range.add_product(seat2)
        voucher, __ = prepare_voucher(_range=new_range)
        voucher, products = get_voucher_and_products_from_code(voucher.code)
        factory = APIRequestFactory()
        request = factory.get('/?code={}&page_size=6'.format(voucher.code))
        request.site = self.site
        request.strategy = DefaultStrategy()
        offers = VoucherViewSet().get_offers(products=products,
                                             request=request,
                                             voucher=voucher)['results']
        self.assertEqual(len(offers), 2)

        products[1].expires = pytz.utc.localize(datetime.datetime.min)
        offers = VoucherViewSet().get_offers(products=products,
                                             request=request,
                                             voucher=voucher)['results']
        self.assertEqual(len(offers), 1)
Ejemplo n.º 13
0
    def get(self, request):
        partner = get_partner_for_site(request)

        sku = request.GET.get('sku', None)
        code = request.GET.get('code', None)

        if not sku:
            return HttpResponseBadRequest(_('No SKU provided.'))

        if code:
            voucher, __ = get_voucher_and_products_from_code(code=code)
        else:
            voucher = None

        try:
            product = StockRecord.objects.get(partner=partner, partner_sku=sku).product
        except StockRecord.DoesNotExist:
            return HttpResponseBadRequest(_('SKU [{sku}] does not exist.').format(sku=sku))

        # If the product isn't available then there's no reason to continue with the basket addition
        purchase_info = request.strategy.fetch_for_product(product)
        if not purchase_info.availability.is_available_to_buy:
            msg = _('Product [{product}] not available to buy.').format(product=product.title)
            return HttpResponseBadRequest(msg)

        # If the product is not an Enrollment Code, we check to see if the user is already
        # enrolled to prevent double-enrollment and/or accidental coupon usage
        if product.get_product_class().name != ENROLLMENT_CODE_PRODUCT_CLASS_NAME:
            try:
                if request.user.is_user_already_enrolled(request, product):
                    logger.warning(
                        'User [%s] attempted to repurchase the [%s] seat of course [%s]',
                        request.user.username,
                        mode_for_seat(product),
                        product.attr.course_key
                    )
                    msg = _('You are already enrolled in {course}.').format(course=product.course.name)
                    return HttpResponseBadRequest(msg)
            except (ConnectionError, SlumberBaseException, Timeout):
                msg = _('An error occurred while retrieving enrollment details. Please try again.')
                return HttpResponseBadRequest(msg)

        # At this point we're either adding an Enrollment Code product to the basket,
        # or the user is adding a Seat product for which they are not already enrolled
        prepare_basket(request, product, voucher)
        return HttpResponseRedirect(reverse('basket:summary'), status=303)
Ejemplo n.º 14
0
    def test_voucher_offers_listing_catalog_query_exception(self, return_value, method):
        """
        Verify the endpoint returns status 200 and an empty list of course offers
        when all product Courses and Stock Records are not found
        and range has a catalog query
        """
        course, seat = self.create_course_and_seat()
        self.mock_dynamic_catalog_course_runs_api(query='*:*', course_run=course)
        new_range, __ = Range.objects.get_or_create(catalog_query='*:*')
        new_range.add_product(seat)
        voucher, __ = prepare_voucher(_range=new_range)
        voucher, products = get_voucher_and_products_from_code(voucher.code)
        request = self.prepare_offers_listing_request(voucher.code)

        with mock.patch(method, mock.Mock(return_value=return_value)):
            offers = VoucherViewSet().get_offers(products=products, request=request, voucher=voucher)
            self.assertEqual(len(offers), 0)
Ejemplo n.º 15
0
    def test_get_offers_for_single_course_voucher(self):
        """ Verify that the course offers data is returned for a single course voucher. """
        course, seat = self.create_course_and_seat()
        new_range = RangeFactory(products=[
            seat,
        ])
        voucher, __ = prepare_voucher(_range=new_range, benefit_value=10)
        voucher, products = get_voucher_and_products_from_code(voucher.code)
        benefit = voucher.offers.first().benefit
        request = self.prepare_offers_listing_request(voucher.code)
        self.mock_course_api_response(course=course)
        offers = VoucherViewSet().get_offers(products=products,
                                             request=request,
                                             voucher=voucher)
        first_offer = offers[0]

        self.assertEqual(len(offers), 1)
        self.assertDictEqual(
            first_offer, {
                'benefit': {
                    'type': benefit.type,
                    'value': benefit.value
                },
                'contains_verified':
                True,
                'course_start_date':
                '2013-02-05T05:00:00Z',
                'id':
                course.id,
                'image_url':
                get_lms_url(
                    '/asset-v1:test+test+test+type@asset+block@images_course_image.jpg'
                ),
                'organization':
                CourseKey.from_string(course.id).org,
                'seat_type':
                course.type,
                'stockrecords':
                serializers.StockRecordSerializer(
                    seat.stockrecords.first()).data,
                'title':
                course.name,
                'voucher_end_date':
                voucher.end_datetime
            })
Ejemplo n.º 16
0
    def offers(self, request):
        """
        Preview the courses offered by the voucher.
        Paginated Response containing the list of course offers will be returned.
        ---
        parameters:
            - name: code
              description: Voucher code
              required: true
              type: string
              paramType: query
              multiple: false
        """
        code = request.GET.get('code', '')

        try:
            voucher, products = get_voucher_and_products_from_code(code)
        except Voucher.DoesNotExist:
            logger.error('Voucher with code %s not found.', code)
            return Response(status=status.HTTP_400_BAD_REQUEST)
        except exceptions.ProductNotFoundError:
            logger.error('No product(s) are associated with this code.')
            return Response(status=status.HTTP_400_BAD_REQUEST)

        query = voucher.offers.first().benefit.range.catalog_query
        if query:
            cache_key = 'voucher_offers_{}'.format(query)
        else:
            cache_key = 'voucher_offers_{}'.format(voucher.id)

        cache_hash = hashlib.md5(cache_key).hexdigest()
        offers = cache.get(cache_hash)
        if not offers:
            try:
                offers = self.get_offers(products, request, voucher)
            except (ConnectionError, SlumberBaseException, Timeout):
                logger.error('Could not get course information.')
                return Response(status=status.HTTP_400_BAD_REQUEST)
            except Http404:
                logger.error('Could not get information for product %s.', products[0].title)
                return Response(status=status.HTTP_404_NOT_FOUND)
            cache.set(cache_hash, offers, settings.COURSES_API_CACHE_TIMEOUT)

        page = self.paginate_queryset(offers)
        return self.get_paginated_response(page)
Ejemplo n.º 17
0
    def test_get_offers(self):
        """ Verify that the course offers data is returned. """
        course, seat = self.create_course_and_seat()
        new_range = RangeFactory(products=[
            seat,
        ])
        voucher, __ = prepare_voucher(_range=new_range, benefit_value=10)
        voucher, products = get_voucher_and_products_from_code(voucher.code)
        benefit = voucher.offers.first().benefit
        request = self.prepare_offers_listing_request(voucher.code)
        self.mock_dynamic_catalog_course_runs_api(
            course_run=course, query=new_range.catalog_query)
        offers = VoucherViewSet().get_offers(products=products,
                                             request=request,
                                             voucher=voucher)
        first_offer = offers[0]

        self.assertEqual(len(offers), 1)
        self.assertDictEqual(
            first_offer, {
                'benefit': {
                    'type': benefit.type,
                    'value': benefit.value
                },
                'contains_verified':
                True,
                'course_start_date':
                '2016-05-01T00:00:00Z',
                'id':
                course.id,
                'image_url':
                'path/to/the/course/image',
                'organization':
                CourseKey.from_string(course.id).org,
                'seat_type':
                course.type,
                'stockrecords':
                serializers.StockRecordSerializer(
                    seat.stockrecords.first()).data,
                'title':
                course.name,
                'voucher_end_date':
                voucher.end_datetime
            })
Ejemplo n.º 18
0
    def offers(self, request):
        """
        Preview the courses offered by the voucher.
        Paginated Response containing the list of course offers will be returned.
        ---
        parameters:
            - name: code
              description: Voucher code
              required: true
              type: string
              paramType: query
              multiple: false
        """
        code = request.GET.get('code', '')

        try:
            voucher, products = get_voucher_and_products_from_code(code)
        except Voucher.DoesNotExist:
            logger.error('Voucher with code %s not found.', code)
            return Response(status=status.HTTP_400_BAD_REQUEST)
        except exceptions.ProductNotFoundError:
            logger.error('No product(s) are associated with this code.')
            return Response(status=status.HTTP_400_BAD_REQUEST)

        try:
            offers_data = self.get_offers(products, request, voucher)
        except (ConnectionError, SlumberBaseException, Timeout):
            logger.error('Could not get course information.')
            return Response(status=status.HTTP_400_BAD_REQUEST)
        except Http404:
            logger.error('Could not get information for product %s.',
                         products[0].title)
            return Response(status=status.HTTP_404_NOT_FOUND)

        next_page = offers_data['next']
        if next_page:
            next_page_query = urlparse(next_page).query
            offers_data['next'] = '{path}?{query}&code={code}'.format(
                code=code,
                path=request.path,
                query=next_page_query,
            )

        return Response(data=offers_data)
Ejemplo n.º 19
0
    def offers(self, request):
        """
        Preview the courses offered by the voucher.
        Paginated Response containing the list of course offers will be returned.
        ---
        parameters:
            - name: code
              description: Voucher code
              required: true
              type: string
              paramType: query
              multiple: false
        """
        code = request.GET.get('code', '')

        try:
            voucher, products = get_voucher_and_products_from_code(code)
        except Voucher.DoesNotExist:
            logger.error('Voucher with code %s not found.', code)
            return Response(status=status.HTTP_400_BAD_REQUEST)
        except exceptions.ProductNotFoundError:
            logger.error('No product(s) are associated with this code.')
            return Response(status=status.HTTP_400_BAD_REQUEST)

        try:
            offers_data = self.get_offers(products, request, voucher)
        except (ConnectionError, SlumberBaseException, Timeout):
            logger.error('Could not get course information.')
            return Response(status=status.HTTP_400_BAD_REQUEST)
        except Http404:
            logger.error('Could not get information for product %s.', products[0].title)
            return Response(status=status.HTTP_404_NOT_FOUND)

        next_page = offers_data['next']
        if next_page:
            next_page_query = urlparse(next_page).query
            offers_data['next'] = '{path}?{query}&code={code}'.format(
                code=code,
                path=request.path,
                query=next_page_query,
            )

        return Response(data=offers_data)
Ejemplo n.º 20
0
    def test_voucher_offers_listing_catalog_query_exception(
            self, return_value, method):
        """
        Verify the endpoint returns status 200 and an empty list of course offers
        when all product Courses and Stock Records are not found
        and range has a catalog query
        """
        course, seat = self.create_course_and_seat()
        self.mock_dynamic_catalog_course_runs_api(query='*:*',
                                                  course_run=course)
        new_range, __ = Range.objects.get_or_create(catalog_query='*:*')
        new_range.add_product(seat)
        voucher, __ = prepare_voucher(_range=new_range)
        voucher, products = get_voucher_and_products_from_code(voucher.code)
        request = self.prepare_offers_listing_request(voucher.code)

        with mock.patch(method, mock.Mock(return_value=return_value)):
            offers = VoucherViewSet().get_offers(products=products,
                                                 request=request,
                                                 voucher=voucher)
            self.assertEqual(len(offers), 0)
Ejemplo n.º 21
0
    def test_omitting_unavailable_seats(self):
        """ Verify an unavailable seat is omitted from offer page results. """
        course1, seat1 = self.create_course_and_seat()
        course2, seat2 = self.create_course_and_seat()
        course_run_info = {
            'count': 2,
            'results': [{
                'key': course1.id,
                'title': course1.name,
                'start': '2016-05-01T00:00:00Z',
                'image': {
                    'src': 'path/to/the/course/image'
                }
            }, {
                'key': course2.id,
                'title': course2.name,
                'start': '2016-05-01T00:00:00Z',
                'image': {
                    'src': 'path/to/the/course/image'
                }
            }]
        }

        self.mock_dynamic_catalog_course_runs_api(query='*:*', course_run_info=course_run_info)
        new_range, __ = Range.objects.get_or_create(catalog_query='*:*')
        new_range.add_product(seat1)
        new_range.add_product(seat2)
        voucher, __ = prepare_voucher(_range=new_range)
        voucher, products = get_voucher_and_products_from_code(voucher.code)
        factory = APIRequestFactory()
        request = factory.get('/?code={}&page_size=6'.format(voucher.code))
        request.site = self.site
        request.strategy = DefaultStrategy()
        offers = VoucherViewSet().get_offers(products=products, request=request, voucher=voucher)
        self.assertEqual(len(offers), 2)

        products[1].expires = pytz.utc.localize(datetime.datetime.min)
        offers = VoucherViewSet().get_offers(products=products, request=request, voucher=voucher)
        self.assertEqual(len(offers), 1)
Ejemplo n.º 22
0
 def test_get_non_existing_voucher(self):
     """ Verify that get_voucher_and_products_from_code() raises exception for a non-existing voucher. """
     with self.assertRaises(Voucher.DoesNotExist):
         get_voucher_and_products_from_code(code='INVALID')
Ejemplo n.º 23
0
 def test_get_non_existing_voucher(self):
     """ Verify that get_voucher_and_products_from_code() raises exception for a non-existing voucher. """
     with self.assertRaises(Voucher.DoesNotExist):
         get_voucher_and_products_from_code(code='INVALID')
Ejemplo n.º 24
0
    def get(self, request):
        partner = get_partner_for_site(request)

        sku = request.GET.get('sku', None)
        code = request.GET.get('code', None)

        if not sku:
            return HttpResponseBadRequest(_('No SKU provided.'))

        if code:
            voucher, __ = get_voucher_and_products_from_code(code=code)
        else:
            voucher = None

        try:
            product = StockRecord.objects.get(partner=partner, partner_sku=sku).product
        except StockRecord.DoesNotExist:
            return HttpResponseBadRequest(_('SKU [{sku}] does not exist.').format(sku=sku))

        # If the product isn't available then there's no reason to continue with the basket addition
        purchase_info = request.strategy.fetch_for_product(product)
        if not purchase_info.availability.is_available_to_buy:
            msg = _('Product [{product}] not available to buy.').format(product=product.title)
            return HttpResponseBadRequest(msg)

        # If the product is not an Enrollment Code, we check to see if the user is already
        # enrolled to prevent double-enrollment and/or accidental coupon usage
        if product.get_product_class().name != ENROLLMENT_CODE_PRODUCT_CLASS_NAME:

            course_key = product.attr.course_key

            # Submit a query to the LMS Enrollment API
            try:
                api = EdxRestApiClient(
                    get_lms_enrollment_base_api_url(),
                    oauth_access_token=request.user.access_token,
                    append_slash=False
                )
                logger.debug(
                    'Getting enrollment information for [%s] in [%s].',
                    request.user.username,
                    course_key
                )
                status = api.enrollment(','.join([request.user.username, course_key])).get()
            except (ConnectionError, SlumberBaseException, Timeout) as ex:
                logger.exception(
                    'Failed to retrieve enrollment details for [%s] in course [%s], Because of [%s]',
                    request.user.username,
                    course_key,
                    ex,
                )
                msg = _('An error occurred while retrieving enrollment details. Please try again.')
                return HttpResponseBadRequest(msg)

            # Enrollment API response received, now perform the actual enrollment check
            username = request.user.username
            seat_type = mode_for_seat(product)
            if status and status.get('mode') == seat_type and status.get('is_active'):
                logger.warning(
                    'User [%s] attempted to repurchase the [%s] seat of course [%s]',
                    username,
                    seat_type,
                    course_key
                )
                msg = _('You are already enrolled in {course}.').format(course=product.course.name)
                return HttpResponseBadRequest(msg)

        # At this point we're either adding an Enrollment Code product to the basket,
        # or the user is adding a Seat product for which they are not already enrolled
        prepare_basket(request, product, voucher)
        return HttpResponseRedirect(reverse('basket:summary'), status=303)