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