def test_basket_switch_data(self): """Verify the correct basket switch data (single vs. multi quantity) is retrieved.""" __, seat, enrollment_code = self.prepare_course_seat_and_enrollment_code() seat_sku = StockRecord.objects.get(product=seat).partner_sku ec_sku = StockRecord.objects.get(product=enrollment_code).partner_sku __, partner_sku = get_basket_switch_data(seat) self.assertEqual(partner_sku, ec_sku) __, partner_sku = get_basket_switch_data(enrollment_code) self.assertEqual(partner_sku, seat_sku)
def test_basket_switch_data(self): """Verify the correct basket switch data (single vs. multi quantity) is retrieved.""" course = CourseFactory() toggle_switch(ENROLLMENT_CODE_SWITCH, True) course.create_or_update_seat('invalid', False, 10, self.partner) seat = course.create_or_update_seat('verified', False, 10, self.partner) seat_sku = StockRecord.objects.get(product=seat).partner_sku enrollment_code = Product.objects.get(product_class__name=ENROLLMENT_CODE_PRODUCT_CLASS_NAME) ec_sku = StockRecord.objects.get(product=enrollment_code).partner_sku __, partner_sku = get_basket_switch_data(seat) self.assertEqual(partner_sku, ec_sku) __, partner_sku = get_basket_switch_data(enrollment_code) self.assertEqual(partner_sku, seat_sku)
def test_basket_switch_data(self): """Verify the correct basket switch data (single vs. multi quantity) is retrieved.""" course = CourseFactory() toggle_switch(ENROLLMENT_CODE_SWITCH, True) seat = course.create_or_update_seat('verified', False, 10, self.partner, create_enrollment_code=True) seat_sku = StockRecord.objects.get(product=seat).partner_sku enrollment_code = Product.objects.get(product_class__name=ENROLLMENT_CODE_PRODUCT_CLASS_NAME) ec_sku = StockRecord.objects.get(product=enrollment_code).partner_sku __, partner_sku = get_basket_switch_data(seat) self.assertEqual(partner_sku, ec_sku) __, partner_sku = get_basket_switch_data(enrollment_code) self.assertEqual(partner_sku, seat_sku)
def test_basket_switch_data(self): """Verify the correct basket switch data (single vs. multi quantity) is retrieved.""" __, seat, enrollment_code = self.prepare_course_seat_and_enrollment_code() seat_sku = StockRecord.objects.get(product=seat).partner_sku ec_sku = StockRecord.objects.get(product=enrollment_code).partner_sku entitlement = create_or_update_course_entitlement( 'verified', 100, self.partner, 'foo-bar', 'Foo Bar Entitlement') __, partner_sku = get_basket_switch_data(seat) self.assertEqual(partner_sku, ec_sku) __, partner_sku = get_basket_switch_data(enrollment_code) self.assertEqual(partner_sku, seat_sku) # Entitlement products should not return a sku for this function __, partner_sku = get_basket_switch_data(entitlement) self.assertIsNone(partner_sku)
def process_basket_lines(self, lines): """ Processes the basket lines and extracts information for the view's context. In addition determines whether: * voucher form should be displayed * switch link (for switching between seat and enrollment code products) should be displayed and returns that information for the basket view context to be updated with it. Args: lines (list): List of basket lines. Returns: context_updates (dict): Containing information with which the context needs to be updated with. lines_data (list): List of information about the basket lines. """ context_updates = { 'order_details_msg': None, 'partner_sku': None, 'switch_link_text': None, 'show_voucher_form': bool(lines), 'is_enrollment_code_purchase': False } lines_data = [] for line in lines: product = line.product if product.is_seat_product or product.is_course_entitlement_product: line_data, _ = self._get_course_data(product) elif product.is_enrollment_code_product: line_data, course = self._get_course_data(product) self._set_single_enrollment_code_warning_if_needed(product, course) context_updates['is_enrollment_code_purchase'] = True context_updates['show_voucher_form'] = False else: line_data = { 'product_title': product.title, 'image_url': None, 'course_key': None, 'product_description': product.description, 'product_subject': None, } context_updates['order_details_msg'] = self._get_order_details_message(product) context_updates['switch_link_text'], context_updates['partner_sku'] = get_basket_switch_data(product) line_data.update({ 'sku': product.stockrecords.first().partner_sku, 'benefit_value': self._get_benefit_value(line), 'enrollment_code': product.is_enrollment_code_product, 'line': line, 'seat_type': self._get_certificate_type_display_value(product), }) lines_data.append(line_data) return context_updates, lines_data
def test_basket_switch_data_for_non_course_run_products(self): """ Verify that no basket switch data is retrieved for product classes that do not relate to course_run instances. """ COURSE_RUN_PRODUCT_CLASSES = ['Seat', 'Enrollment Code'] for product_class in ProductClass.objects.all(): product = ProductFactory( product_class=product_class, title='{} product title'.format(product_class.name), categories=None, stockrecords__partner=self.partner ) # Verify that the StockRecord hunt is only attempted for course run products with mock.patch('ecommerce.extensions.basket.utils._find_seat_enrollment_toggle_sku') as mock_track: _, _ = get_basket_switch_data(product) if product.product_class.name in COURSE_RUN_PRODUCT_CLASSES: self.assertEqual(mock_track.call_count, 1) else: mock_track.assert_not_called()
def _process_basket_lines(self, lines): """Processes the basket lines and extracts information for the view's context. In addition determines whether: * verification message should be displayed * voucher form should be displayed * switch link (for switching between seat and enrollment code products) should be displayed and returns that information for the basket view context to be updated with it. Args: lines (list): List of basket lines. Returns: context_updates (dict): Containing information with which the context needs to be updated with. lines_data (list): List of information about the basket lines. """ display_verification_message = False lines_data = [] show_voucher_form = True is_enrollment_code_purchase = False switch_link_text = partner_sku = order_details_msg = None for line in lines: if line.product.is_seat_product or line.product.is_course_entitlement_product: line_data = self._get_course_data(line.product) certificate_type = line.product.attr.certificate_type if getattr(line.product.attr, 'id_verification_required', False) and certificate_type != 'credit': display_verification_message = True if line.product.is_course_entitlement_product: order_details_msg = _( 'After you complete your order you will be able to select course dates from your dashboard.' ) else: if certificate_type == 'verified': order_details_msg = _( 'After you complete your order you will be automatically enrolled ' 'in the verified track of the course.') elif certificate_type == 'credit': order_details_msg = _( 'After you complete your order you will receive credit for your course.' ) else: order_details_msg = _( 'After you complete your order you will be automatically enrolled in the course.' ) elif line.product.is_enrollment_code_product: line_data = self._get_course_data(line.product) is_enrollment_code_purchase = True show_voucher_form = False order_details_msg = _( '{paragraph_start}By purchasing, you and your organization agree to the following terms:' '{paragraph_end} {ul_start} {li_start}Each code is valid for the one course covered and can be ' 'used only one time.{li_end} ' '{li_start}You are responsible for distributing codes to your learners in your organization.' '{li_end} {li_start}Each code will expire in one year from date of purchase or, if earlier, once ' 'the course is closed.{li_end} {li_start}If a course is not designated as self-paced, you should ' 'confirm that a course run is available before expiration. {li_end} {li_start}You may not resell ' 'codes to third parties.{li_end} ' '{li_start}All edX for Business Sales are final and not eligible for refunds.{li_end}{ul_end} ' '{paragraph_start}You will receive an email at {user_email} with your enrollment code(s). ' '{paragraph_end}').format( paragraph_start='<p>', paragraph_end='</p>', ul_start='<ul>', li_start='<li>', li_end='</li>', ul_end='</ul>', user_email=self.request.user.email) else: line_data = { 'product_title': line.product.title, 'image_url': None, 'product_description': line.product.description } # Get variables for the switch link that toggles from enrollment codes and seat. switch_link_text, partner_sku = get_basket_switch_data( line.product) try: if line.has_discount: benefit = self.request.basket.applied_offers().values( )[0].benefit benefit_value = format_benefit_value(benefit) else: benefit_value = None except IndexError: logger.exception( 'Basket {%d} line{%d} has discount value {%s} ', self.request.basket.id, line.id, line.discount_value) benefit_value = None product_course_id = line.product.course_id.split('+') line_data.update({ 'sku': line.product.stockrecords.first().partner_sku, 'benefit_value': benefit_value, 'enrollment_code': line.product.is_enrollment_code_product, 'line': line, 'seat_type': self._determine_product_type(line.product), 'product_course_id': product_course_id[1] if len(product_course_id) > 1 else '', }) lines_data.append(line_data) context_updates = { 'display_verification_message': display_verification_message, 'order_details_msg': order_details_msg, 'partner_sku': partner_sku, 'show_voucher_form': show_voucher_form, 'switch_link_text': switch_link_text, 'is_enrollment_code_purchase': is_enrollment_code_purchase } return context_updates, lines_data
def _process_basket_lines(self, lines): """Processes the basket lines and extracts information for the view's context. In addition determines whether: * verification message should be displayed * voucher form should be displayed * switch link (for switching between seat and enrollment code products) should be displayed and returns that information for the basket view context to be updated with it. Args: lines (list): List of basket lines. Returns: context_updates (dict): Containing information with which the context needs to be updated with. lines_data (list): List of information about the basket lines. """ display_verification_message = False lines_data = [] show_voucher_form = True switch_link_text = partner_sku = order_details_msg = None for line in lines: if line.product.is_seat_product or line.product.is_course_entitlement_product: line_data = self._get_course_data(line.product) certificate_type = line.product.attr.certificate_type if getattr(line.product.attr, 'id_verification_required', False) and certificate_type != 'credit': display_verification_message = True if line.product.is_course_entitlement_product: order_details_msg = _( 'After you complete your order you will be able to select course dates from your dashboard.' ) else: if certificate_type == 'verified': order_details_msg = _( 'After you complete your order you will be automatically enrolled ' 'in the verified track of the course.') elif certificate_type == 'credit': order_details_msg = _( 'After you complete your order you will receive credit for your course.' ) else: order_details_msg = _( 'After you complete your order you will be automatically enrolled in the course.' ) elif line.product.is_enrollment_code_product: line_data = self._get_course_data(line.product) show_voucher_form = False order_details_msg = _( 'You will receive an email at {user_email} with your enrollment code(s).' ).format(user_email=self.request.user.email) else: line_data = { 'product_title': line.product.title, 'image_url': None, 'product_description': line.product.description } # TODO: handle these links for multi-line baskets. if self.request.site.siteconfiguration.enable_enrollment_codes: # Get variables for the switch link that toggles from enrollment codes and seat. switch_link_text, partner_sku = get_basket_switch_data( line.product) if line.has_discount: benefit = self.request.basket.applied_offers().values( )[0].benefit benefit_value = format_benefit_value(benefit) else: benefit_value = None line_data.update({ 'sku': line.product.stockrecords.first().partner_sku, 'benefit_value': benefit_value, 'enrollment_code': line.product.is_enrollment_code_product, 'line': line, 'seat_type': self._determine_product_type(line.product), }) lines_data.append(line_data) context_updates = { 'display_verification_message': display_verification_message, 'order_details_msg': order_details_msg, 'partner_sku': partner_sku, 'show_voucher_form': show_voucher_form, 'switch_link_text': switch_link_text } return context_updates, lines_data
def get_context_data(self, **kwargs): context = super(BasketSummaryView, self).get_context_data(**kwargs) formset = context.get('formset', []) lines = context.get('line_list', []) lines_data = [] is_verification_required = is_bulk_purchase = False switch_link_text = partner_sku = '' basket = self.request.basket site = self.request.site site_configuration = site.siteconfiguration for line in lines: course_key = CourseKey.from_string(line.product.attr.course_key) course_name = None image_url = None short_description = None try: course = get_course_info_from_catalog(self.request.site, course_key) try: image_url = course['image']['src'] except (KeyError, TypeError): image_url = '' short_description = course.get('short_description', '') course_name = course.get('title', '') except (ConnectionError, SlumberBaseException, Timeout): logger.exception('Failed to retrieve data from Catalog Service for course [%s].', course_key) if self.request.site.siteconfiguration.enable_enrollment_codes: # Get variables for the switch link that toggles from enrollment codes and seat. switch_link_text, partner_sku = get_basket_switch_data(line.product) if line.product.get_product_class().name == ENROLLMENT_CODE_PRODUCT_CLASS_NAME: is_bulk_purchase = True # Iterate on message storage so all messages are marked as read. # This will hide the success messages when a user updates the quantity # for an item in the basket. list(messages.get_messages(self.request)) if line.has_discount: benefit = basket.applied_offers().values()[0].benefit benefit_value = format_benefit_value(benefit) else: benefit_value = None lines_data.append({ 'seat_type': self._determine_seat_type(line.product), 'course_name': course_name, 'course_key': course_key, 'image_url': image_url, 'course_short_description': short_description, 'benefit_value': benefit_value, 'enrollment_code': line.product.get_product_class().name == ENROLLMENT_CODE_PRODUCT_CLASS_NAME, 'line': line, }) user = self.request.user context.update({ 'analytics_data': prepare_analytics_data( user, self.request.site.siteconfiguration.segment_key, unicode(course_key) ), 'enable_client_side_checkout': False, }) if site_configuration.client_side_payment_processor \ and waffle.flag_is_active(self.request, CLIENT_SIDE_CHECKOUT_FLAG_NAME): payment_processor_class = site_configuration.get_client_side_payment_processor_class() if payment_processor_class: payment_processor = payment_processor_class(site) context.update({ 'enable_client_side_checkout': True, 'payment_form': PaymentForm(user=user, initial={'basket': basket}, label_suffix=''), 'payment_url': payment_processor.client_side_payment_url, }) else: msg = 'Unable to load client-side payment processor [{processor}] for ' \ 'site configuration [{sc}]'.format(processor=site_configuration.client_side_payment_processor, sc=site_configuration.id) raise SiteConfigurationError(msg) # Check product attributes to determine if ID verification is required for this basket try: is_verification_required = line.product.attr.id_verification_required \ and line.product.attr.certificate_type != 'credit' except AttributeError: pass context.update({ 'free_basket': context['order_total'].incl_tax == 0, 'payment_processors': site_configuration.get_payment_processors(), 'homepage_url': get_lms_url(''), 'formset_lines_data': zip(formset, lines_data), 'is_verification_required': is_verification_required, 'min_seat_quantity': 1, 'is_bulk_purchase': is_bulk_purchase, 'switch_link_text': switch_link_text, 'partner_sku': partner_sku, }) return context
def get_context_data(self, **kwargs): context = super(BasketSummaryView, self).get_context_data(**kwargs) formset = context.get('formset', []) lines = context.get('line_list', []) lines_data = [] is_verification_required = is_bulk_purchase = False switch_link_text = partner_sku = '' for line in lines: course_key = CourseKey.from_string(line.product.attr.course_key) course_name = None image_url = None short_description = None try: course = get_course_info_from_lms(course_key) image_url = get_lms_url(course['media']['course_image']['uri']) short_description = course['short_description'] course_name = course['name'] except (ConnectionError, SlumberBaseException, Timeout): logger.exception('Failed to retrieve data from Course API for course [%s].', course_key) # Set to true if any course in basket has bulk purchase scenario if line.product.get_product_class().name == ENROLLMENT_CODE_PRODUCT_CLASS_NAME: is_bulk_purchase = True # Iterate on message storage so all messages are marked as read list(messages.get_messages(self.request)) # Get variables for alternative basket view switch_link_text, partner_sku = get_basket_switch_data(line.product) if line.has_discount: benefit = self.request.basket.applied_offers().values()[0].benefit benefit_value = format_benefit_value(benefit) else: benefit_value = None lines_data.append({ 'seat_type': self._determine_seat_type(line.product), 'course_name': course_name, 'course_key': course_key, 'image_url': image_url, 'course_short_description': short_description, 'benefit_value': benefit_value, 'enrollment_code': line.product.get_product_class().name == ENROLLMENT_CODE_PRODUCT_CLASS_NAME, 'line': line, }) context.update({ 'analytics_data': prepare_analytics_data( self.request.user, self.request.site.siteconfiguration.segment_key, unicode(course_key) ), }) # Check product attributes to determine if ID verification is required for this basket try: is_verification_required = is_verification_required or line.product.attr.id_verification_required except AttributeError: pass context.update({ 'free_basket': context['order_total'].incl_tax == 0, 'payment_processors': self.request.site.siteconfiguration.get_payment_processors(), 'homepage_url': get_lms_url(''), 'formset_lines_data': zip(formset, lines_data), 'is_verification_required': is_verification_required, 'min_seat_quantity': 1, 'is_bulk_purchase': is_bulk_purchase, 'switch_link_text': switch_link_text, 'partner_sku': partner_sku, }) return context
def _process_basket_lines(self, lines): """Processes the basket lines and extracts information for the view's context. In addition determines whether: * verification message should be displayed * voucher form should be displayed * switch link (for switching between seat and enrollment code products) should be displayed and returns that information for the basket view context to be updated with it. Args: lines (list): List of basket lines. Returns: context_updates (dict): Containing information with which the context needs to be updated with. lines_data (list): List of information about the basket lines. """ display_verification_message = False lines_data = [] show_voucher_form = True switch_link_text = partner_sku = order_details_msg = None for line in lines: product_class_name = line.product.get_product_class().name if product_class_name == 'Seat': line_data = self._get_course_data(line.product) certificate_type = line.product.attr.certificate_type if getattr(line.product.attr, 'id_verification_required', False) and certificate_type != 'credit': display_verification_message = True if certificate_type == 'verified': order_details_msg = _( 'You will be automatically enrolled in the verified track' ' of the course upon completing your order.' ) elif certificate_type == 'credit': order_details_msg = _('You will receive your credit upon completing your order.') else: order_details_msg = _( 'You will be automatically enrolled in the course upon completing your order.' ) elif product_class_name == 'Enrollment Code': line_data = self._get_course_data(line.product) show_voucher_form = False order_details_msg = _( 'You will receive an email at {user_email} with your enrollment code(s).' ).format(user_email=self.request.user.email) else: line_data = { 'product_title': line.product.title, 'image_url': None, 'product_description': line.product.description } # TODO: handle these links for multi-line baskets. if self.request.site.siteconfiguration.enable_enrollment_codes: # Get variables for the switch link that toggles from enrollment codes and seat. switch_link_text, partner_sku = get_basket_switch_data(line.product) if line.has_discount: benefit = self.request.basket.applied_offers().values()[0].benefit benefit_value = format_benefit_value(benefit) else: benefit_value = None line_data.update({ 'benefit_value': benefit_value, 'enrollment_code': line.product.get_product_class().name == ENROLLMENT_CODE_PRODUCT_CLASS_NAME, 'line': line, 'seat_type': self._determine_seat_type(line.product), }) lines_data.append(line_data) context_updates = { 'display_verification_message': display_verification_message, 'order_details_msg': order_details_msg, 'partner_sku': partner_sku, 'show_voucher_form': show_voucher_form, 'switch_link_text': switch_link_text } return context_updates, lines_data
def process_basket_lines(self, lines, request=None): """ Processes the basket lines and extracts information for the view's context. In addition determines whether: * verification message should be displayed * voucher form should be displayed * switch link (for switching between seat and enrollment code products) should be displayed and returns that information for the basket view context to be updated with it. Args: lines (list): List of basket lines. Returns: context_updates (dict): Containing information with which the context needs to be updated with. lines_data (list): List of information about the basket lines. """ context_updates = { 'display_verification_message': False, 'order_details_msg': None, 'partner_sku': None, 'switch_link_text': None, 'show_voucher_form': bool(lines), 'is_enrollment_code_purchase': False } # Check if user's country is India to update line sku -mohit741 isIndian = False if request and request.user is not None and not request.user.is_anonymous: profile = request.user.account_details(request) isIndian = profile['country'] == 'IN' lines_data = [] for line in lines: product = line.product if product.is_seat_product or product.is_course_entitlement_product: line_data, _ = self._get_course_data(product) # TODO this is only used by hosted_checkout_basket template, which may no longer be # used. Consider removing both. if self._is_id_verification_required(product): context_updates['display_verification_message'] = True elif product.is_enrollment_code_product: line_data, course = self._get_course_data(product) self._set_single_enrollment_code_warning_if_needed( product, course) context_updates['is_enrollment_code_purchase'] = True context_updates['show_voucher_form'] = False else: line_data = { 'product_title': product.title, 'image_url': None, 'course_key': None, 'product_description': product.description } context_updates[ 'order_details_msg'] = self._get_order_details_message(product) context_updates['switch_link_text'], context_updates[ 'partner_sku'] = get_basket_switch_data(product) stocks = product.stockrecords.all() line_data.update({ 'sku': stocks[0].partner_sku if not isIndian and len(stocks) is 1 else stocks[1].partner_sku, 'benefit_value': self._get_benefit_value(line), 'enrollment_code': product.is_enrollment_code_product, 'line': line, 'seat_type': self._get_certificate_type_display_value(product), }) lines_data.append(line_data) return context_updates, lines_data