Пример #1
0
    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)
Пример #2
0
    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)
Пример #3
0
 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)
Пример #4
0
    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)
Пример #5
0
    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)
Пример #6
0
    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
Пример #7
0
    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()
Пример #8
0
    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
Пример #9
0
    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
Пример #10
0
    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
Пример #11
0
    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
Пример #12
0
    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
Пример #13
0
    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