示例#1
0
    def test_get_or_create_catalog(self):
        """Verify that the proper catalog is fetched."""
        stock_record = self.seat.stockrecords.first()
        self.catalog.stock_records.add(stock_record)

        self.assertEqual(self.catalog.id, 1)

        existing_catalog, created = get_or_create_catalog(
            name='Test',
            partner=self.partner,
            stock_record_ids=[stock_record.id]
        )
        self.assertFalse(created)
        self.assertEqual(self.catalog, existing_catalog)
        self.assertEqual(Catalog.objects.count(), 1)

        course_id = 'sku/test2/course'
        course = Course.objects.create(id=course_id, name='Test Course 2')
        seat_2 = course.create_or_update_seat('verified', False, 0, self.partner)
        stock_record_2 = seat_2.stockrecords.first()

        new_catalog, created = get_or_create_catalog(
            name='Test',
            partner=self.partner,
            stock_record_ids=[stock_record.id, stock_record_2.id]
        )
        self.assertTrue(created)
        self.assertNotEqual(self.catalog, new_catalog)
        self.assertEqual(Catalog.objects.count(), 2)
示例#2
0
    def test_get_or_create_catalog(self):
        """Verify that the proper catalog is fetched."""
        stock_record = self.seat.stockrecords.first()
        self.catalog.stock_records.add(stock_record)

        existing_catalog, created = get_or_create_catalog(
            name='Test',
            partner=self.partner,
            stock_record_ids=[stock_record.id])
        self.assertFalse(created)
        self.assertEqual(self.catalog, existing_catalog)
        self.assertEqual(Catalog.objects.count(), 1)

        course_id = 'sku/test2/course'
        course = CourseFactory(id=course_id,
                               name='Test Course 2',
                               partner=self.partner)
        seat_2 = course.create_or_update_seat('verified', False, 0)
        stock_record_2 = seat_2.stockrecords.first()

        new_catalog, created = get_or_create_catalog(
            name='Test',
            partner=self.partner,
            stock_record_ids=[stock_record.id, stock_record_2.id])
        self.assertTrue(created)
        self.assertNotEqual(self.catalog, new_catalog)
        self.assertEqual(Catalog.objects.count(), 2)
示例#3
0
    def test_get_or_create_catalog(self):
        """Verify that the proper catalog is fetched."""
        self.catalog.stock_records.add(StockRecord.objects.first())

        self.assertEqual(self.catalog.id, 1)

        existing_catalog, created = get_or_create_catalog(
            name='Test',
            partner=self.partner,
            stock_record_ids=[1]
        )
        self.assertFalse(created)
        self.assertEqual(self.catalog, existing_catalog)
        self.assertEqual(Catalog.objects.count(), 1)

        course_id = 'sku/test2/course'
        course = Course.objects.create(id=course_id, name='Test Course 2')
        course.create_or_update_seat('verified', False, 0, self.partner)

        new_catalog, created = get_or_create_catalog(
            name='Test',
            partner=self.partner,
            stock_record_ids=[1, 2]
        )
        self.assertTrue(created)
        self.assertNotEqual(self.catalog, new_catalog)
        self.assertEqual(Catalog.objects.count(), 2)
示例#4
0
    def get_coupon_catalog(cls, stock_record_ids, partner):
        """
        Validate stock_record_ids and return a coupon catalog if applicable.

        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 not stock_record_ids:
            return None

        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:
                    validation_message = 'Course mode not supported'
                    raise ValidationError(validation_message)
            except AttributeError:
                validation_message = 'Course mode not supported'
                raise ValidationError(validation_message)

        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
        )
        return coupon_catalog
示例#5
0
    def get_coupon_catalog(cls, stock_record_ids, partner):
        """
        Validate stock_record_ids and return a coupon catalog if applicable.

        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 not stock_record_ids:
            return None

        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:
                    validation_message = 'Course mode not supported'
                    raise ValidationError(validation_message, code=status.HTTP_400_BAD_REQUEST)
            except AttributeError:
                validation_message = 'Course mode not supported'
                raise ValidationError(validation_message, code=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
        )
        return coupon_catalog
示例#6
0
    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)
示例#7
0
    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)
示例#8
0
    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 and price 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[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['category_ids'])
            client, __ = Client.objects.get_or_create(username=client_username)

            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
            )

            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,
            }

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

            basket = self.add_product_to_basket(
                product=coupon_product,
                client=client,
                site=request.site,
                partner=partner
            )

            # 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)

            return Response(response_data, status=status.HTTP_200_OK)
示例#9
0
    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 and price 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[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

            client, __ = Client.objects.get_or_create(username=client_username)

            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
            )

            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
            }

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

            basket = self.add_product_to_basket(
                product=coupon_product,
                client=client,
                site=request.site,
                partner=partner
            )

            # 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)

            return Response(response_data, status=status.HTTP_200_OK)
示例#10
0
    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[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', None)
            max_uses = request.data.get('max_uses', None)

            # 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 is used only for
            # ONCE_PER_CUSTOMER types
            if max_uses and voucher_type == Voucher.ONCE_PER_CUSTOMER:
                max_uses = int(max_uses)
            else:
                max_uses = None

            # We currently do not support multi-use voucher types.
            if voucher_type == Voucher.MULTI_USE:
                raise NotImplementedError('Multi-use voucher types are not supported')

            # 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.
            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:
                        raise Exception('Course mode not supported')
                except AttributeError:
                    raise Exception('Course mode not supported')

            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
            )

            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,
            }

            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)