def get_offers_from_catalog(self, request, voucher): """ Helper method for collecting offers from catalog query or enterprise catalog. Args: request (WSGIRequest): Request data. voucher (Voucher): Oscar Voucher for which the offers are returned. Returns: A list of dictionaries with retrieved offers and a link to the next page of the Course Discovery results. """ benefit = voucher.best_offer.benefit condition = voucher.best_offer.condition # Pull all catalog related data from the offer. catalog_query = benefit.range.catalog_query if benefit.range else None catalog_id = benefit.range.course_catalog if benefit.range else None enterprise_customer = (condition.enterprise_customer_uuid or (benefit.range and benefit.range.enterprise_customer)) enterprise_catalog = (condition.enterprise_customer_catalog_uuid or (benefit.range and benefit.range.enterprise_customer_catalog)) if catalog_id: catalog = fetch_course_catalog(request.site, catalog_id) catalog_query = catalog.get("query") if catalog else catalog_query # There is no catalog related data specified for this condition, so return None. if not catalog_query and not enterprise_customer: return None, None if enterprise_catalog: response = get_enterprise_catalog( site=request.site, enterprise_catalog=enterprise_catalog, limit=request.GET.get('limit', DEFAULT_CATALOG_PAGE_SIZE), page=request.GET.get('page'), ) elif catalog_query: response = get_catalog_course_runs( site=request.site, query=catalog_query, limit=request.GET.get('limit', DEFAULT_CATALOG_PAGE_SIZE), offset=request.GET.get('offset'), ) else: logger.warning( 'User is trying to redeem Voucher %s, but no catalog information is configured!', voucher.code) return [], None next_page = response['next'] offers = self.convert_catalog_response_to_offers( request, voucher, response) return offers, next_page
def preview(self, request): """ Preview the results of the catalog query. A list of course runs, indicating a course run presence within the catalog, will be returned. --- parameters: - name: query description: Elasticsearch querystring query required: true type: string paramType: query multiple: false """ query = request.GET.get('query') seat_types = request.GET.get('seat_types') offset = request.GET.get('offset') limit = request.GET.get('limit', DEFAULT_CATALOG_PAGE_SIZE) if not (query and seat_types): detail = {} if not query: detail['query'] = 'The query parameter is required.' if not seat_types: detail['seat_types'] = 'The seat_type parameter is required.' raise ValidationError(detail=detail) seat_types = seat_types.split(',') try: response = get_catalog_course_runs( site=request.site, query=query, limit=limit, offset=offset ) results = response['results'] course_ids = [result['key'] for result in results] seats = serializers.ProductSerializer( Product.objects.filter( course_id__in=course_ids, attributes__name='certificate_type', attribute_values__value_text__in=seat_types ), many=True, context={'request': request} ).data data = { 'next': response['next'], 'seats': seats } return Response(data=data) except (ConnectionError, SlumberBaseException, Timeout): logger.error('Unable to connect to Catalog API.') return Response(status=status.HTTP_400_BAD_REQUEST)
def get_course_ids_from_voucher(site, voucher): """ Get site base list of course run keys from the provided voucher object. Arguments: site: (django.contrib.sites.Site) site instance voucher (Voucher): voucher class object Returns: list of course ids """ voucher_offer = voucher.offers.first() offer_range = voucher_offer.condition.range if offer_range.course_catalog: try: course_catalog = get_course_catalogs(site=site, resource_id=offer_range.course_catalog) except (ConnectionError, SlumberBaseException, Timeout): logger.error('Unable to connect to Course Catalog service for course catalogs.') return None try: course_runs = get_catalog_course_runs(site, course_catalog.get('query'))['results'] except (ConnectionError, SlumberBaseException, Timeout, KeyError): logger.error('Unable to get course runs from Course Catalog service.') return None voucher_course_ids = [course_run.get('key') for course_run in course_runs if course_run.get('key')] elif offer_range.catalog_query: try: course_runs = get_catalog_course_runs(site, offer_range.catalog_query)['results'] except (ConnectionError, SlumberBaseException, Timeout, KeyError): logger.error('Unable to get course runs from Course Catalog service.') return None voucher_course_ids = [course_run.get('key') for course_run in course_runs if course_run.get('key')] else: stock_records = offer_range.catalog.stock_records.all() seats = Product.objects.filter(id__in=[sr.product.id for sr in stock_records]) voucher_course_ids = [seat.course_id for seat in seats] return voucher_course_ids
def preview(self, request): """ Preview the results of the catalog query. A list of course runs, indicating a course run presence within the catalog, will be returned. --- parameters: - name: query description: Elasticsearch querystring query required: true type: string paramType: query multiple: false """ query = request.GET.get('query') seat_types = request.GET.get('seat_types') offset = request.GET.get('offset') limit = request.GET.get('limit', DEFAULT_CATALOG_PAGE_SIZE) if query and seat_types: seat_types = seat_types.split(',') try: response = get_catalog_course_runs( site=request.site, query=query, limit=limit, offset=offset ) results = response['results'] course_ids = [result['key'] for result in results] seats = serializers.ProductSerializer( Product.objects.filter( course_id__in=course_ids, attributes__name='certificate_type', attribute_values__value_text__in=seat_types ), many=True, context={'request': request} ).data data = { 'next': response['next'], 'seats': seats } return Response(data=data) except (ConnectionError, SlumberBaseException, Timeout): logger.error('Unable to connect to Course Catalog service.') return Response(status=status.HTTP_400_BAD_REQUEST) return Response(status=status.HTTP_400_BAD_REQUEST)
def get_offers_from_catalog(self, request, voucher, catalog_query, enterprise_catalog): """ Helper method for collecting offers from catalog query or enterprise catalog. Args: request (WSGIRequest): Request data. voucher (Voucher): Oscar Voucher for which the offers are returned. catalog_query (str): The query for the Course Discovery. Returns: A list of dictionaries with retrieved offers and a link to the next page of the Course Discovery results. """ offers = [] benefit = voucher.offers.first().benefit course_seat_types = benefit.range.course_seat_types multiple_credit_providers = False credit_provider_price = None response = {} if enterprise_catalog: response = get_enterprise_catalog( site=request.site, enterprise_catalog=enterprise_catalog, limit=request.GET.get('limit', DEFAULT_CATALOG_PAGE_SIZE), page=request.GET.get('page'), ) elif catalog_query: response = get_catalog_course_runs( site=request.site, query=catalog_query, limit=request.GET.get('limit', DEFAULT_CATALOG_PAGE_SIZE), offset=request.GET.get('offset'), ) next_page = response['next'] products, stock_records, course_run_metadata = self.retrieve_course_objects( response['results'], course_seat_types) contains_verified_course = (course_seat_types == 'verified') for product in products: # Omit unavailable seats from the offer results so that one seat does not cause an # error message for every seat in the query result. if not request.strategy.fetch_for_product( product).availability.is_available_to_buy: logger.info( '%s is unavailable to buy. Omitting it from the results.', product) continue course_id = product.course_id course_catalog_data = course_run_metadata[course_id] if course_seat_types == 'credit': # Omit credit seats for which the user is not eligible or which the user already bought. if request.user.is_eligible_for_credit(product.course_id): if Order.objects.filter(user=request.user, lines__product=product).exists(): continue else: continue credit_seats = Product.objects.filter( parent=product.parent, attributes__name='credit_provider') if credit_seats.count() > 1: multiple_credit_providers = True credit_provider_price = None else: multiple_credit_providers = False credit_provider_price = StockRecord.objects.get( product=product).price_excl_tax try: stock_record = stock_records.get(product__id=product.id) except StockRecord.DoesNotExist: stock_record = None logger.error('Stock Record for product %s not found.', product.id) try: course = Course.objects.get(id=course_id) except Course.DoesNotExist: # pragma: no cover course = None logger.error('Course %s not found.', course_id) if course_catalog_data and course and stock_record: offers.append( self.get_course_offer_data( benefit=benefit, course=course, course_info=course_catalog_data, credit_provider_price=credit_provider_price, multiple_credit_providers=multiple_credit_providers, is_verified=contains_verified_course, product=product, stock_record=stock_record, voucher=voucher)) return offers, next_page