コード例 #1
0
ファイル: coupons.py プロジェクト: open-craft/ecommerce
    def create_update_data_dict(self, data, fields):
        """
        Creates a dictionary for updating model attributes.

        Arguments:
            data (QueryDict): Request data
            fields (list): List of updatable model fields

        Returns:
            update_dict (dict): Dictionary that will be used to update model objects.
        """
        update_dict = {}

        for field in fields:
            if field in data:
                if field == 'course_seat_types':
                    value = prepare_course_seat_types(data.get(field))
                    update_dict[field] = value
                elif field == 'max_uses':
                    value = data.get(field)
                    update_dict['max_global_applications'] = value
                else:
                    value = data.get(field)
                    update_dict[field.replace('invoice_', '')] = value
        return update_dict
コード例 #2
0
ファイル: coupons.py プロジェクト: xavierchan/ecommerce
    def create_update_data_dict(self, data, fields):
        """
        Creates a dictionary for updating model attributes.

        Arguments:
            data (QueryDict): Request data
            fields (list): List of updatable model fields

        Returns:
            update_dict (dict): Dictionary that will be used to update model objects.
        """
        update_dict = {}

        for field in fields:
            if field in data:
                if field == 'course_seat_types':
                    value = prepare_course_seat_types(data.get(field))
                    update_dict[field] = value
                elif field == 'max_uses':
                    value = data.get(field)
                    update_dict['max_global_applications'] = value
                else:
                    value = data.get(field)
                    update_dict[field.replace('invoice_', '')] = value
        return update_dict
コード例 #3
0
ファイル: coupons.py プロジェクト: kumarsandeep91/ecommerce
 def create_update_data_dict(self, request_data, request_data_key, update_dict, update_dict_key):
     """
     Adds the value from request data to the update data dictionary
     Arguments:
         request_data (QueryDict): Request data
         request_data_key (str): Request data dictionary key
         update_dict (dict): Dictionary containing the coupon update data
         update_dict_key (str): Update data dictionary key
     """
     if request_data_key in request_data:
         value = request_data.get(request_data_key)
         update_dict[update_dict_key] = prepare_course_seat_types(value) \
             if update_dict_key == COURSE_SEAT_TYPES else value
コード例 #4
0
ファイル: coupons.py プロジェクト: siddhartharay007/ecommerce
 def create_update_data_dict(self, request_data, request_data_key,
                             update_dict, update_dict_key):
     """
     Adds the value from request data to the update data dictionary
     Arguments:
         request_data (QueryDict): Request data
         request_data_key (str): Request data dictionary key
         update_dict (dict): Dictionary containing the coupon update data
         update_dict_key (str): Update data dictionary key
     """
     value = request_data.get(request_data_key, '')
     if value:
         update_dict[update_dict_key] = prepare_course_seat_types(value) \
             if update_dict_key == COURSE_SEAT_TYPES else value
コード例 #5
0
ファイル: coupons.py プロジェクト: eduNEXT/edunext-ecommerce
    def clean_voucher_request_data(cls, request_data, partner):
        """
        Helper method to return cleaned request data for voucher creation or
        raise validation error with error code.

        Arguments:
            request (dict): request's data with voucher data
            partner (str): the request's site's partner

        """
        benefit_type = request_data.get('benefit_type')
        category_data = request_data.get('category')
        code = request_data.get('code')
        course_catalog_data = request_data.get('course_catalog')
        enterprise_customer_data = request_data.get('enterprise_customer')
        course_seat_types = request_data.get('course_seat_types')
        max_uses = request_data.get('max_uses')
        stock_record_ids = request_data.get('stock_record_ids')
        voucher_type = request_data.get('voucher_type')
        program_uuid = request_data.get('program_uuid')
        notify_email = request_data.get('notify_email')

        if benefit_type not in (Benefit.PERCENTAGE, Benefit.FIXED,):
            raise ValidationError('Benefit type [{type}] is not allowed'.format(type=benefit_type))

        if code and Voucher.does_exist(code):
            validation_message = 'A coupon with code {code} already exists.'.format(code=code)
            raise ValidationError(validation_message)

        if course_seat_types:
            try:
                course_seat_types = prepare_course_seat_types(course_seat_types)
            except (AttributeError, TypeError) as exception:
                validation_message = 'Invalid course seat types data: {}'.format(str(exception))
                raise ValidationError(validation_message)

        try:
            category = Category.objects.get(name=category_data['name'])
        except Category.DoesNotExist:
            validation_message = 'Category "{category_name}" not found.'.format(category_name=category_data['name'])
            # FIXME 404 is the wrong response code to use here.
            raise ValidationError(validation_message, code=status.HTTP_404_NOT_FOUND)
        except (KeyError, TypeError):
            validation_message = 'Invalid Coupon Category data.'
            raise ValidationError(validation_message)

        try:
            course_catalog = course_catalog_data['id'] if course_catalog_data else None
        except (KeyError, TypeError):
            validation_message = 'Unexpected catalog data format received for coupon.'
            raise ValidationError(validation_message)

        try:
            enterprise_customer = enterprise_customer_data['id'] if enterprise_customer_data else None
            enterprise_customer_name = enterprise_customer_data.get('name') if enterprise_customer_data else None
        except (KeyError, TypeError):
            validation_message = 'Unexpected EnterpriseCustomer data format received for coupon.'
            raise ValidationError(validation_message)

        if notify_email:
            try:
                validate_email(notify_email)
            except ValidationError:
                raise ValidationError('Notification email must be a valid email address.')

        coupon_catalog = cls.get_coupon_catalog(stock_record_ids, partner)

        return {
            'benefit_type': benefit_type,
            'benefit_value': request_data.get('benefit_value'),
            'coupon_catalog': coupon_catalog,
            'catalog_query': request_data.get('catalog_query'),
            'category': category,
            'code': code,
            'course_catalog': course_catalog,
            'course_seat_types': course_seat_types,
            'email_domains': request_data.get('email_domains'),
            'end_datetime': request_data.get('end_datetime'),
            'enterprise_customer': enterprise_customer,
            'enterprise_customer_name': enterprise_customer_name,
            'enterprise_customer_catalog': request_data.get('enterprise_customer_catalog'),
            'max_uses': max_uses,
            'note': request_data.get('note'),
            'partner': partner,
            'price': request_data.get('price'),
            'quantity': request_data.get('quantity'),
            'start_datetime': request_data.get('start_datetime'),
            'title': request_data.get('title'),
            'voucher_type': voucher_type,
            'program_uuid': program_uuid,
            'notify_email': notify_email,
            'contract_discount_type': request_data.get('contract_discount_type'),
            'contract_discount_value': request_data.get('contract_discount_value'),
            'prepaid_invoice_amount': request_data.get('prepaid_invoice_amount'),
            'sales_force_id': request_data.get('sales_force_id'),
        }
コード例 #6
0
ファイル: coupons.py プロジェクト: ilozano2/ecommerce
    def clean_voucher_request_data(cls, request):
        """
        Helper method to return cleaned request data for voucher creation or
        raise validation error with error code.

        Arguments:
            request (HttpRequest): request with voucher data

        """
        category_data = request.data.get('category')
        code = request.data.get('code')
        course_catalog_data = request.data.get('course_catalog')
        enterprise_customer_data = request.data.get('enterprise_customer')
        course_seat_types = request.data.get('course_seat_types')
        max_uses = request.data.get('max_uses')
        partner = request.site.siteconfiguration.partner
        stock_record_ids = request.data.get('stock_record_ids')
        voucher_type = request.data.get('voucher_type')

        if code and Voucher.does_exist(code):
            validation_message = 'A coupon with code {code} already exists.'.format(
                code=code)
            raise ValidationError(validation_message,
                                  code=status.HTTP_400_BAD_REQUEST)

        if course_seat_types:
            try:
                course_seat_types = prepare_course_seat_types(
                    course_seat_types)
            except (AttributeError, TypeError) as exception:
                validation_message = 'Invalid course seat types data: {}'.format(
                    exception.message)
                raise ValidationError(validation_message,
                                      code=status.HTTP_400_BAD_REQUEST)

        try:
            category = Category.objects.get(name=category_data['name'])
        except Category.DoesNotExist:
            validation_message = 'Category "{category_name}" not found.'.format(
                category_name=category_data['name'])
            raise ValidationError(validation_message,
                                  code=status.HTTP_404_NOT_FOUND)
        except (KeyError, TypeError):
            validation_message = 'Invalid Coupon Category data.'
            raise ValidationError(validation_message,
                                  code=status.HTTP_400_BAD_REQUEST)

        try:
            course_catalog = course_catalog_data[
                'id'] if course_catalog_data else None
        except (KeyError, TypeError):
            validation_message = 'Unexpected catalog data format received for coupon.'
            raise ValidationError(validation_message,
                                  code=status.HTTP_400_BAD_REQUEST)

        try:
            enterprise_customer = enterprise_customer_data[
                'id'] if enterprise_customer_data else None
        except (KeyError, TypeError):
            validation_message = 'Unexpected EnterpriseCustomer data format received for coupon.'
            raise ValidationError(validation_message,
                                  code=status.HTTP_400_BAD_REQUEST)

        coupon_catalog = cls.get_coupon_catalog(stock_record_ids, partner)

        return {
            'benefit_type': request.data.get('benefit_type'),
            'benefit_value': request.data.get('benefit_value'),
            'coupon_catalog': coupon_catalog,
            'catalog_query': request.data.get('catalog_query'),
            'category': category,
            'code': code,
            'course_catalog': course_catalog,
            'course_seat_types': course_seat_types,
            'email_domains': request.data.get('email_domains'),
            'end_datetime': request.data.get('end_datetime'),
            'enterprise_customer': enterprise_customer,
            'max_uses': max_uses,
            'note': request.data.get('note'),
            'partner': partner,
            'price': request.data.get('price'),
            'quantity': request.data.get('quantity'),
            'start_datetime': request.data.get('start_datetime'),
            'title': request.data.get('title'),
            'voucher_type': voucher_type,
        }
コード例 #7
0
ファイル: coupons.py プロジェクト: siddhartharay007/ecommerce
    def create(self, request, *args, **kwargs):
        """Adds coupon to the user's basket.

        Expects request array to contain all the necessary data (listed out below).
        This information is then used to create a coupon product, add to a
        basket and create an order from it.

        Arguments:
            request (HttpRequest): With parameters title, client_username,
            stock_record_ids, start_date, end_date, code, benefit_type, benefit_value,
            voucher_type, quantity, price, category and note in the body.

        Returns:
            200 if the order was created successfully; the basket ID is included in the response
                body along with the order ID and payment information.
            401 if an unauthenticated request is denied permission to access the endpoint.
            429 if the client has made requests at a rate exceeding that allowed by the configured rate limit.
            500 if an error occurs when attempting to create a coupon.
        """
        with transaction.atomic():
            title = request.data[AC.KEYS.TITLE]
            client_username = request.data[AC.KEYS.CLIENT_USERNAME]
            stock_record_ids = request.data.get(AC.KEYS.STOCK_RECORD_IDS)
            start_date = dateutil.parser.parse(
                request.data[AC.KEYS.START_DATE])
            end_date = dateutil.parser.parse(request.data[AC.KEYS.END_DATE])
            code = request.data[AC.KEYS.CODE]
            benefit_type = request.data[AC.KEYS.BENEFIT_TYPE]
            benefit_value = request.data[AC.KEYS.BENEFIT_VALUE]
            voucher_type = request.data[AC.KEYS.VOUCHER_TYPE]
            quantity = request.data[AC.KEYS.QUANTITY]
            price = request.data[AC.KEYS.PRICE]
            partner = request.site.siteconfiguration.partner
            categories = Category.objects.filter(
                id__in=request.data[AC.KEYS.CATEGORY_IDS])
            client, __ = BusinessClient.objects.get_or_create(
                name=client_username)
            note = request.data.get('note')
            max_uses = request.data.get('max_uses')
            catalog_query = request.data.get(CATALOG_QUERY)
            course_seat_types = request.data.get(COURSE_SEAT_TYPES)

            if course_seat_types:
                course_seat_types = prepare_course_seat_types(
                    course_seat_types)

            # Maximum number of uses can be set for each voucher type and disturb
            # the predefined behaviours of the different voucher types. Therefor
            # here we enforce that the max_uses variable can't be used for SINGLE_USE
            # voucher types.
            if max_uses and voucher_type != Voucher.SINGLE_USE:
                max_uses = int(max_uses)
            else:
                max_uses = None

            # When a black-listed course mode is received raise an exception.
            # Audit modes do not have a certificate type and therefore will raise
            # an AttributeError exception.
            if stock_record_ids:
                seats = Product.objects.filter(
                    stockrecords__id__in=stock_record_ids)
                for seat in seats:
                    try:
                        if seat.attr.certificate_type in settings.BLACK_LIST_COUPON_COURSE_MODES:
                            return Response('Course mode not supported',
                                            status=status.HTTP_400_BAD_REQUEST)
                    except AttributeError:
                        return Response('Course mode not supported',
                                        status=status.HTTP_400_BAD_REQUEST)

                stock_records_string = ' '.join(
                    str(id) for id in stock_record_ids)
                coupon_catalog, __ = get_or_create_catalog(
                    name='Catalog for stock records: {}'.format(
                        stock_records_string),
                    partner=partner,
                    stock_record_ids=stock_record_ids)
            else:
                coupon_catalog = None

            data = {
                'partner': partner,
                'title': title,
                'benefit_type': benefit_type,
                'benefit_value': benefit_value,
                'catalog': coupon_catalog,
                'end_date': end_date,
                'code': code,
                'quantity': quantity,
                'start_date': start_date,
                'voucher_type': voucher_type,
                'categories': categories,
                'note': note,
                'max_uses': max_uses,
                'catalog_query': catalog_query,
                'course_seat_types': course_seat_types
            }

            coupon_product = self.create_coupon_product(title, price, data)

            basket = prepare_basket(request, coupon_product)

            # Create an order now since payment is handled out of band via an invoice.
            response_data = self.create_order_for_invoice(
                basket, coupon_id=coupon_product.id, client=client)

            return Response(response_data, status=status.HTTP_200_OK)
コード例 #8
0
 def test_prepare_course_seat_types(self, course_seat_types,
                                    expected_result):
     """Verify prepare course seat types return correct value."""
     self.assertEqual(prepare_course_seat_types(course_seat_types),
                      expected_result)
コード例 #9
0
ファイル: coupons.py プロジェクト: uzairr/ecommerce
    def create(self, request, *args, **kwargs):
        """Adds coupon to the user's basket.

        Expects request array to contain all the necessary data (listed out below).
        This information is then used to create a coupon product, add to a
        basket and create an order from it.

        Arguments:
            request (HttpRequest): With parameters title, client,
            stock_record_ids, start_date, end_date, code, benefit_type, benefit_value,
            voucher_type, quantity, price, category, note and invoice data in the body.

        Returns:
            200 if the order was created successfully; the basket ID is included in the response
                body along with the order ID and payment information.
            400 if a custom code is received that already exists,
                if a course mode is selected that is not supported.
            401 if an unauthenticated request is denied permission to access the endpoint.
            429 if the client has made requests at a rate exceeding that allowed by the configured rate limit.
            500 if an error occurs when attempting to create a coupon.
        """
        category_data = request.data.get('category')
        code = request.data.get('code')
        course_seat_types = request.data.get('course_seat_types')
        max_uses = request.data.get('max_uses')
        partner = request.site.siteconfiguration.partner
        stock_record_ids = request.data.get('stock_record_ids')
        voucher_type = request.data.get('voucher_type')

        with transaction.atomic():
            if code:
                try:
                    Voucher.objects.get(code=code)
                    return Response(
                        'A coupon with code {code} already exists.'.format(
                            code=code),
                        status=status.HTTP_400_BAD_REQUEST)
                except Voucher.DoesNotExist:
                    pass

            if course_seat_types:
                course_seat_types = prepare_course_seat_types(
                    course_seat_types)

            try:
                category = Category.objects.get(name=category_data['name'])
            except Category.DoesNotExist:
                return Response('Category {category_name} not found.'.format(
                    category_name=category_data['name']),
                                status=status.HTTP_404_NOT_FOUND)
            except KeyError:
                return Response('Invalid Coupon Category data.',
                                status=status.HTTP_400_BAD_REQUEST)

            # Maximum number of uses can be set for each voucher type and disturb
            # the predefined behaviours of the different voucher types. Therefor
            # here we enforce that the max_uses variable can't be used for SINGLE_USE
            # voucher types.
            if max_uses and voucher_type != Voucher.SINGLE_USE:
                max_uses = int(max_uses)
            else:
                max_uses = None

            # When a black-listed course mode is received raise an exception.
            # Audit modes do not have a certificate type and therefore will raise
            # an AttributeError exception.
            if stock_record_ids:
                seats = Product.objects.filter(
                    stockrecords__id__in=stock_record_ids)
                for seat in seats:
                    try:
                        if seat.attr.certificate_type in settings.BLACK_LIST_COUPON_COURSE_MODES:
                            return Response('Course mode not supported',
                                            status=status.HTTP_400_BAD_REQUEST)
                    except AttributeError:
                        return Response('Course mode not supported',
                                        status=status.HTTP_400_BAD_REQUEST)

                stock_records_string = ' '.join(
                    str(id) for id in stock_record_ids)
                coupon_catalog, __ = get_or_create_catalog(
                    name='Catalog for stock records: {}'.format(
                        stock_records_string),
                    partner=partner,
                    stock_record_ids=stock_record_ids)
            else:
                coupon_catalog = None

            coupon_product = create_coupon_product(
                benefit_type=request.data.get('benefit_type'),
                benefit_value=request.data.get('benefit_value'),
                catalog=coupon_catalog,
                catalog_query=request.data.get('catalog_query'),
                category=category,
                code=code,
                course_seat_types=course_seat_types,
                email_domains=request.data.get('email_domains'),
                end_datetime=dateutil.parser.parse(
                    request.data.get('end_datetime')),
                max_uses=max_uses,
                note=request.data.get('note'),
                partner=partner,
                price=request.data.get('price'),
                quantity=request.data.get('quantity'),
                start_datetime=dateutil.parser.parse(
                    request.data.get('start_datetime')),
                title=request.data.get('title'),
                voucher_type=voucher_type)

            basket = prepare_basket(request, coupon_product)

            # Create an order now since payment is handled out of band via an invoice.
            client, __ = BusinessClient.objects.get_or_create(
                name=request.data.get('client'))
            invoice_data = self.create_update_data_dict(
                data=request.data, fields=Invoice.UPDATEABLE_INVOICE_FIELDS)
            response_data = self.create_order_for_invoice(
                basket,
                coupon_id=coupon_product.id,
                client=client,
                invoice_data=invoice_data)

            return Response(response_data, status=status.HTTP_200_OK)
コード例 #10
0
ファイル: test_utils.py プロジェクト: open-craft/ecommerce
 def test_prepare_course_seat_types(self, course_seat_types, expected_result):
     """Verify prepare course seat types return correct value."""
     self.assertEqual(prepare_course_seat_types(course_seat_types), expected_result)
コード例 #11
0
ファイル: coupons.py プロジェクト: open-craft/ecommerce
    def clean_voucher_request_data(cls, request):
        """
        Helper method to return cleaned request data for voucher creation or
        raise validation error with error code.

        Arguments:
            request (HttpRequest): request with voucher data

        """
        category_data = request.data.get('category')
        code = request.data.get('code')
        course_catalog_data = request.data.get('course_catalog')
        enterprise_customer_data = request.data.get('enterprise_customer')
        course_seat_types = request.data.get('course_seat_types')
        max_uses = request.data.get('max_uses')
        partner = request.site.siteconfiguration.partner
        stock_record_ids = request.data.get('stock_record_ids')
        voucher_type = request.data.get('voucher_type')

        if code and Voucher.does_exist(code):
            validation_message = 'A coupon with code {code} already exists.'.format(code=code)
            raise ValidationError(validation_message, code=status.HTTP_400_BAD_REQUEST)

        if course_seat_types:
            try:
                course_seat_types = prepare_course_seat_types(course_seat_types)
            except (AttributeError, TypeError) as exception:
                validation_message = 'Invalid course seat types data: {}'.format(exception.message)
                raise ValidationError(validation_message, code=status.HTTP_400_BAD_REQUEST)

        try:
            category = Category.objects.get(name=category_data['name'])
        except Category.DoesNotExist:
            validation_message = 'Category "{category_name}" not found.'.format(category_name=category_data['name'])
            raise ValidationError(validation_message, code=status.HTTP_404_NOT_FOUND)
        except (KeyError, TypeError):
            validation_message = 'Invalid Coupon Category data.'
            raise ValidationError(validation_message, code=status.HTTP_400_BAD_REQUEST)

        try:
            course_catalog = course_catalog_data['id'] if course_catalog_data else None
        except (KeyError, TypeError):
            validation_message = 'Unexpected catalog data format received for coupon.'
            raise ValidationError(validation_message, code=status.HTTP_400_BAD_REQUEST)

        try:
            enterprise_customer = enterprise_customer_data['id'] if enterprise_customer_data else None
        except (KeyError, TypeError):
            validation_message = 'Unexpected EnterpriseCustomer data format received for coupon.'
            raise ValidationError(validation_message, code=status.HTTP_400_BAD_REQUEST)

        coupon_catalog = cls.get_coupon_catalog(stock_record_ids, partner)

        return {
            'benefit_type': request.data.get('benefit_type'),
            'benefit_value': request.data.get('benefit_value'),
            'coupon_catalog': coupon_catalog,
            'catalog_query': request.data.get('catalog_query'),
            'category': category,
            'code': code,
            'course_catalog': course_catalog,
            'course_seat_types': course_seat_types,
            'email_domains': request.data.get('email_domains'),
            'end_datetime': request.data.get('end_datetime'),
            'enterprise_customer': enterprise_customer,
            'max_uses': max_uses,
            'note': request.data.get('note'),
            'partner': partner,
            'price': request.data.get('price'),
            'quantity': request.data.get('quantity'),
            'start_datetime': request.data.get('start_datetime'),
            'title': request.data.get('title'),
            'voucher_type': voucher_type,
        }
コード例 #12
0
ファイル: coupons.py プロジェクト: kumarsandeep91/ecommerce
    def create(self, request, *args, **kwargs):
        """Adds coupon to the user's basket.

        Expects request array to contain all the necessary data (listed out below).
        This information is then used to create a coupon product, add to a
        basket and create an order from it.

        Arguments:
            request (HttpRequest): With parameters title, client,
            stock_record_ids, start_date, end_date, code, benefit_type, benefit_value,
            voucher_type, quantity, price, category, note and invoice data in the body.

        Returns:
            200 if the order was created successfully; the basket ID is included in the response
                body along with the order ID and payment information.
            400 if a custom code is received that already exists,
                if a course mode is selected that is not supported.
            401 if an unauthenticated request is denied permission to access the endpoint.
            429 if the client has made requests at a rate exceeding that allowed by the configured rate limit.
            500 if an error occurs when attempting to create a coupon.
        """
        with transaction.atomic():
            title = request.data[AC.KEYS.TITLE]
            client_username = request.data[CLIENT]
            stock_record_ids = request.data.get(AC.KEYS.STOCK_RECORD_IDS)
            start_date = dateutil.parser.parse(request.data[AC.KEYS.START_DATE])
            end_date = dateutil.parser.parse(request.data[AC.KEYS.END_DATE])
            code = request.data[AC.KEYS.CODE]
            benefit_type = request.data[AC.KEYS.BENEFIT_TYPE]
            benefit_value = request.data[AC.KEYS.BENEFIT_VALUE]
            voucher_type = request.data[AC.KEYS.VOUCHER_TYPE]
            quantity = request.data[AC.KEYS.QUANTITY]
            price = request.data[AC.KEYS.PRICE]
            partner = request.site.siteconfiguration.partner
            categories = Category.objects.filter(id__in=request.data[AC.KEYS.CATEGORY_IDS])
            client, __ = BusinessClient.objects.get_or_create(name=client_username)
            note = request.data.get('note')
            max_uses = request.data.get('max_uses')
            catalog_query = request.data.get(CATALOG_QUERY)
            course_seat_types = request.data.get(COURSE_SEAT_TYPES)

            if code:
                try:
                    Voucher.objects.get(code=code)
                    return Response(
                        'A coupon with code {code} already exists.'.format(code=code),
                        status=status.HTTP_400_BAD_REQUEST
                    )
                except Voucher.DoesNotExist:
                    pass

            invoice_data = self.retrieve_invoice_data(request.data)

            if course_seat_types:
                course_seat_types = prepare_course_seat_types(course_seat_types)

            # Maximum number of uses can be set for each voucher type and disturb
            # the predefined behaviours of the different voucher types. Therefor
            # here we enforce that the max_uses variable can't be used for SINGLE_USE
            # voucher types.
            if max_uses and voucher_type != Voucher.SINGLE_USE:
                max_uses = int(max_uses)
            else:
                max_uses = None

            # When a black-listed course mode is received raise an exception.
            # Audit modes do not have a certificate type and therefore will raise
            # an AttributeError exception.
            if stock_record_ids:
                seats = Product.objects.filter(stockrecords__id__in=stock_record_ids)
                for seat in seats:
                    try:
                        if seat.attr.certificate_type in settings.BLACK_LIST_COUPON_COURSE_MODES:
                            return Response('Course mode not supported', status=status.HTTP_400_BAD_REQUEST)
                    except AttributeError:
                        return Response('Course mode not supported', status=status.HTTP_400_BAD_REQUEST)

                stock_records_string = ' '.join(str(id) for id in stock_record_ids)
                coupon_catalog, __ = get_or_create_catalog(
                    name='Catalog for stock records: {}'.format(stock_records_string),
                    partner=partner,
                    stock_record_ids=stock_record_ids
                )
            else:
                coupon_catalog = None

            data = {
                'partner': partner,
                'title': title,
                'benefit_type': benefit_type,
                'benefit_value': benefit_value,
                'catalog': coupon_catalog,
                'end_date': end_date,
                'code': code,
                'quantity': quantity,
                'start_date': start_date,
                'voucher_type': voucher_type,
                'categories': categories,
                'note': note,
                'max_uses': max_uses,
                'catalog_query': catalog_query,
                'course_seat_types': course_seat_types
            }

            coupon_product = self.create_coupon_product(title, price, data)

            basket = prepare_basket(request, coupon_product)

            # Create an order now since payment is handled out of band via an invoice.
            response_data = self.create_order_for_invoice(
                basket, coupon_id=coupon_product.id, client=client, invoice_data=invoice_data
            )

            return Response(response_data, status=status.HTTP_200_OK)