示例#1
0
    def test_notify_purchaser(self, mock_task):
        """ Verify the notification is scheduled if the site has notifications enabled
        and the refund is for a course seat.
        """
        site_configuration = self.site.siteconfiguration
        site_configuration.send_refund_notifications = True

        user = UserFactory()

        course = CourseFactory()
        price = Decimal(100.00)
        product = course.create_or_update_seat('verified', True, price, self.partner)

        basket = create_basket(empty=True)
        basket.site = self.site
        basket.add_product(product)

        order = create_order(basket=basket, user=user)
        order_url = get_receipt_page_url(site_configuration, order.number)

        refund = Refund.create_with_lines(order, order.lines.all())

        with LogCapture(REFUND_MODEL_LOGGER_NAME) as l:
            refund._notify_purchaser()  # pylint: disable=protected-access

        msg = 'Course refund notification scheduled for Refund [{}].'.format(refund.id)
        l.check(
            (REFUND_MODEL_LOGGER_NAME, 'INFO', msg)
        )

        amount = format_currency(order.currency, price)
        mock_task.assert_called_once_with(
            user.email, refund.id, amount, course.name, order.number, order_url, site_code=self.partner.short_code
        )
示例#2
0
    def test_proper_code(self):
        """ Verify that proper information is returned when a valid code is provided. """
        course = CourseFactory()
        seat = course.create_or_update_seat('verified', True, 50, self.partner)
        sr = StockRecord.objects.get(product=seat)
        catalog = Catalog.objects.create(name='Test catalog', partner=self.partner)
        catalog.stock_records.add(sr)
        range_ = RangeFactory(catalog=catalog)
        self.prepare_voucher(range_=range_)

        course_info = {
            "media": {
                "course_image": {
                    "uri": "/asset-v1:edX+DemoX+Demo_Course+type@asset+block@images_course_image.jpg"
                }
            },
            "name": "edX Demonstration Course",
        }
        course_info_json = json.dumps(course_info)
        course_url = get_lms_url('api/courses/v1/courses/{}/'.format(course.id))
        httpretty.register_uri(httpretty.GET, course_url, body=course_info_json, content_type='application/json')

        url = self.offer_url + '?code={}'.format('COUPONTEST')
        response = self.client.get(url)
        self.assertEqual(response.context['course']['name'], _('edX Demonstration Course'))
        self.assertEqual(response.context['code'], _('COUPONTEST'))
示例#3
0
    def setUp(self):
        super(CouponViewSetTest, self).setUp()
        self.user = self.create_user(is_staff=True)
        self.client.login(username=self.user.username, password=self.password)

        course = CourseFactory(id='edx/Demo_Course/DemoX')
        self.seat = course.create_or_update_seat('verified', True, 50, self.partner)

        self.catalog = Catalog.objects.create(partner=self.partner)
        self.coupon_data = {
            'title': 'Tešt Čoupon',
            'partner': self.partner,
            'benefit_type': Benefit.PERCENTAGE,
            'benefit_value': 100,
            'catalog': self.catalog,
            'end_datetime': str(now() + datetime.timedelta(days=10)),
            'enterprise_customer': {'id': str(uuid4()).decode('utf-8')},
            'code': '',
            'quantity': 2,
            'start_datetime': str(now() - datetime.timedelta(days=1)),
            'voucher_type': Voucher.ONCE_PER_CUSTOMER,
            'category': {'name': self.category.name},
            'note': None,
            'max_uses': None,
            'catalog_query': None,
            'course_seat_types': None,
            'email_domains': None,
        }
    def setUp(self):
        super(CouponViewSetTest, self).setUp()
        self.user = self.create_user(is_staff=True)
        self.client.login(username=self.user.username, password=self.password)

        course = CourseFactory(id='edx/Demo_Course/DemoX')
        course.create_or_update_seat('verified', True, 50, self.partner)

        self.catalog = Catalog.objects.create(partner=self.partner)
        self.product_class, __ = ProductClass.objects.get_or_create(name='Coupon')
        self.coupon_data = {
            'title': 'Test Coupon',
            'partner': self.partner,
            'benefit_type': Benefit.PERCENTAGE,
            'benefit_value': 100,
            'catalog': self.catalog,
            'end_date': '2020-1-1',
            'code': '',
            'quantity': 2,
            'start_date': '2015-1-1',
            'voucher_type': Voucher.ONCE_PER_CUSTOMER,
            'categories': [self.category],
            'note': None,
            'max_uses': None,
        }
示例#5
0
class VoucherRemoveMessagesViewTests(CouponMixin, CourseCatalogTestMixin, TestCase):
    """ VoucherRemoveMessagesView view tests. """

    def setUp(self):
        super(VoucherRemoveMessagesViewTests, self).setUp()
        self.user = self.create_user()
        self.client.login(username=self.user.username, password=self.password)

        self.course = CourseFactory()
        self.course.create_or_update_seat('verified', True, 50, self.partner)
        self.product = self.course.create_or_update_seat('verified', False, 0, self.partner)
        self.voucher, __ = prepare_voucher(code=COUPON_CODE)

        self.request = RequestFactory().request()
        # Fallback storage is needed in tests with messages
        setattr(self.request, 'session', 'session')
        messages = FallbackStorage(self.request)
        setattr(self.request, '_messages', messages)
        self.request.user = self.user

        basket = factories.BasketFactory(owner=self.user, site=self.site)
        basket.add_product(self.product, 1)
        self.request.basket = basket

        self.voucher_remove_view = VoucherRemoveMessagesView()

    def test_remove_voucher_pk_conversion(self):
        """ Verify that voucher primary key is converted to integer """
        self.voucher_remove_view.post(self.request, pk=self.voucher.id)
        request_message = list(get_messages(self.request))[-1].message
        self.assertEqual(
            str(request_message),
            "No voucher found with id '{0}'".format(self.voucher.id)
        )
示例#6
0
    def create_course_and_seat(
            self, course_id=None, seat_type='verified', id_verification=False, price=10, partner=None
    ):
        """
        Create a course and a seat from that course.

        Arguments:
            course_name (str): name of the course
            seat_type (str): the seat type
            id_verification (bool): if id verification is required
            price (int): seat price
            partner(Partner): the site partner

        Returns:
            The created course and seat.
        """

        if not partner:
            partner = PartnerFactory()
        if not course_id:
            course = CourseFactory()
        else:
            course = CourseFactory(id=course_id)

        seat = course.create_or_update_seat(seat_type, id_verification, price, partner)
        return course, seat
示例#7
0
 def test_restricted_course_mode(self, mode):
     """Test that an exception is raised when a black-listed course mode is used."""
     course = CourseFactory(id='black/list/mode')
     seat = course.create_or_update_seat(mode, False, 0, self.partner)
     # Seats derived from a migrated "audit" mode do not have a certificate_type attribute.
     if mode == 'audit':
         seat = ProductFactory()
     self.data.update({'stock_record_ids': [StockRecord.objects.get(product=seat).id]})
     self.assert_post_response_status(self.data)
    def setUp(self):
        super(CouponRedeemViewTests, self).setUp()
        self.user = self.create_user()
        self.client.login(username=self.user.username, password=self.password)
        course = CourseFactory()
        self.seat = course.create_or_update_seat('verified', True, 50, self.partner)

        self.catalog = Catalog.objects.create(partner=self.partner)
        self.catalog.stock_records.add(StockRecord.objects.get(product=self.seat))
示例#9
0
 def setUp(self):
     super(EnrollmentCodeFulfillmentModuleTests, self).setUp()
     toggle_switch(ENROLLMENT_CODE_SWITCH, True)
     course = CourseFactory()
     course.create_or_update_seat('verified', True, 50, self.partner)
     enrollment_code = Product.objects.get(product_class__name=ENROLLMENT_CODE_PRODUCT_CLASS_NAME)
     user = UserFactory()
     basket = BasketFactory()
     basket.add_product(enrollment_code, self.QUANTITY)
     self.order = factories.create_order(number=1, basket=basket, user=user)
示例#10
0
 def prepare_course_information(self):
     """ Helper function to prepare an API endpoint that provides course information. """
     course = CourseFactory(name='Test course')
     seat = course.create_or_update_seat('verified', True, 50, self.partner)
     stock_record = StockRecord.objects.get(product=seat)
     catalog = Catalog.objects.create(name='Test catalog', partner=self.partner)
     catalog.stock_records.add(stock_record)
     _range = RangeFactory(catalog=catalog)
     self.mock_course_api_response(course=course)
     return _range
示例#11
0
    def test_filter_product_class(self):
        """ Verify the method supports filtering by product class or the parent product's class. """
        course = CourseFactory()
        seat = course.create_or_update_seat('verified', True, 1, self.partner)
        parent = course.parent_seat_product
        product_class_name = self.seat_product_class.name
        queryset = Product.objects.all()

        actual = list(self.filter.filter_product_class(queryset, product_class_name))
        self.assertListEqual(actual, [seat, parent])
示例#12
0
 def test_restricted_course_mode(self, mode):
     """Test that an exception is raised when a black-listed course mode is used."""
     course = CourseFactory(id='black/list/mode')
     seat = course.create_or_update_seat(mode, False, 0, self.partner)
     # Seats derived from a migrated "audit" mode do not have a certificate_type attribute.
     if mode == 'audit':
         seat = ProductFactory()
     self.data.update({'stock_record_ids': [StockRecord.objects.get(product=seat).id]})
     response = self.client.post(COUPONS_LINK, data=self.data, format='json')
     self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
    def setUp(self):
        super(BasketSingleItemViewTests, self).setUp()
        self.user = self.create_user()
        self.client.login(username=self.user.username, password=self.password)

        course = CourseFactory()
        course.create_or_update_seat('verified', True, 50, self.partner)
        product = course.create_or_update_seat('verified', False, 0, self.partner)
        self.stock_record = StockRecordFactory(product=product, partner=self.partner)
        self.catalog = Catalog.objects.create(partner=self.partner)
        self.catalog.stock_records.add(self.stock_record)
示例#14
0
 def test_enrollment_code_seat_type(self):
     """Verify the correct seat type attribute is retrieved."""
     course = CourseFactory()
     toggle_switch(ENROLLMENT_CODE_SWITCH, True)
     course.create_or_update_seat('verified', False, 10, self.partner)
     enrollment_code = Product.objects.get(product_class__name=ENROLLMENT_CODE_PRODUCT_CLASS_NAME)
     self.create_basket_and_add_product(enrollment_code)
     self.mock_course_api_response(course)
     response = self.client.get(self.path)
     self.assertEqual(response.status_code, 200)
     line_data = response.context['formset_lines_data'][0][1]
     self.assertEqual(line_data['seat_type'], _(enrollment_code.attr.seat_type.capitalize()))
示例#15
0
    def test_get_transaction_parameters_with_quoted_product_title(self):
        """ Verify quotes are removed from item name """
        course = CourseFactory(id='a/b/c/d', name='Course with "quotes"')
        product = course.create_or_update_seat(self.CERTIFICATE_TYPE, False, 20, self.partner)

        basket = factories.create_basket(empty=True)
        basket.add_product(product)
        basket.owner = factories.UserFactory()
        basket.site = self.site
        basket.save()

        response = self.processor.get_transaction_parameters(basket)
        self.assertEqual(response['item_0_name'], 'Seat in Course with quotes with test-certificate-type certificate')
示例#16
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)
    def test_prof_ed_stale_product_removal(self):
        """
        Verify that stale professional education seats are deleted if they have not been purchased.
        """
        course = CourseFactory()
        course.create_or_update_seat('professional', False, 0, self.partner)
        self.assertEqual(course.products.count(), 2)

        course.create_or_update_seat('professional', True, 0, self.partner)
        self.assertEqual(course.products.count(), 2)

        product_mode = course.products.first()
        self.assertEqual(product_mode.attr.id_verification_required, True)
        self.assertEqual(product_mode.attr.certificate_type, 'professional')
示例#18
0
    def test_create_seat_with_enrollment_code(self):
        """Verify an enrollment code product is created."""
        course = CourseFactory()
        seat_type = 'verified'
        price = 5
        toggle_switch(ENROLLMENT_CODE_SWITCH, True)
        course.create_or_update_seat(seat_type, True, price, self.partner)

        enrollment_code = Product.objects.get(product_class__name=ENROLLMENT_CODE_PRODUCT_CLASS_NAME)
        self.assertEqual(enrollment_code.attr.course_key, course.id)
        self.assertEqual(enrollment_code.attr.seat_type, seat_type)

        stock_record = StockRecord.objects.get(product=enrollment_code)
        self.assertEqual(stock_record.price_excl_tax, price)
        self.assertEqual(stock_record.price_currency, settings.OSCAR_DEFAULT_CURRENCY)
        self.assertEqual(stock_record.partner, self.partner)
    def test_course_publish_successfully(self):
        """ Verify all courses are successfully published."""

        second_course = CourseFactory.create()
        self.create_course_ids_file(self.tmp_file_path, [self.course.id, second_course.id])
        expected = (
            (
                LOGGER_NAME,
                "INFO",
                "Publishing 2 courses."
            ),
            (
                LOGGER_NAME,
                "INFO",
                u"(1/2) Successfully published {}.".format(self.course.id)
            ),
            (
                LOGGER_NAME,
                "INFO",
                u"(2/2) Successfully published {}.".format(second_course.id)),
            (
                LOGGER_NAME,
                "INFO",
                "All 2 courses successfully published."
            )
        )
        with mock.patch.object(Course, 'publish_to_lms', autospec=True) as mock_publish:
            mock_publish.return_value = None
            with LogCapture(LOGGER_NAME) as lc:
                call_command('publish_to_lms', course_ids_file=self.tmp_file_path)
                lc.check(*expected)
        # Check that the mocked function was called twice.
        self.assertListEqual(mock_publish.call_args_list, [call(self.course), call(second_course)])
示例#20
0
class UtilTests(CourseCatalogTestMixin, TestCase):

    def setUp(self):
        super(UtilTests, self).setUp()
        self.course = CourseFactory()
        self.verified_seat = self.course.create_or_update_seat('verified', False, 100, self.partner)
        self.stock_record = StockRecord.objects.filter(product=self.verified_seat).first()
        self.seat_price = self.stock_record.price_excl_tax
        self._range = RangeFactory(products=[self.verified_seat, ])

        self.percentage_benefit = BenefitFactory(type=Benefit.PERCENTAGE, range=self._range, value=35.00)
        self.value_benefit = BenefitFactory(type=Benefit.FIXED, range=self._range, value=self.seat_price - 10)

    def test_format_benefit_value(self):
        """ format_benefit_value(benefit) should format benefit value based on benefit type """
        benefit_value = format_benefit_value(self.percentage_benefit)
        self.assertEqual(benefit_value, '35%')

        benefit_value = format_benefit_value(self.value_benefit)
        self.assertEqual(benefit_value, currency(self.seat_price - 10))

    @ddt.data(
        ('1.0', '1'),
        ('5000.0', '5000'),
        ('1.45000', '1.45'),
        ('5000.40000', '5000.4'),
    )
    @ddt.unpack
    def test_remove_exponent_and_trailing_zeros(self, value, expected):
        """
        _remove_exponent_and_trailing_zeros(decimal) should remove exponent and trailing zeros
        from decimal number
        """
        decimal = _remove_exponent_and_trailing_zeros(Decimal(value))
        self.assertEqual(decimal, Decimal(expected))
示例#21
0
    def test_already_verified_student(self, mode, id_verification):
        """
        Verify the view return HTTP 400 if the student is already enrolled as verified student in the course
        """
        course = CourseFactory()
        self.mock_enrollment_api_success(course.id, mode=mode)
        product = course.create_or_update_seat(mode, id_verification, 0, self.partner)
        stock_record = StockRecordFactory(product=product, partner=self.partner)
        catalog = Catalog.objects.create(partner=self.partner)
        catalog.stock_records.add(stock_record)

        url = '{path}?sku={sku}'.format(path=self.path, sku=stock_record.partner_sku)
        expected_content = 'You are already enrolled in {product}.'.format(product=product.course.name)
        response = self.client.get(url)
        self.assertEqual(response.status_code, 400)
        self.assertEqual(response.content, expected_content)
示例#22
0
    def test_course_information_error(self):
        """ Verify a response is returned when course information is not accessable. """
        course = CourseFactory()
        seat = course.create_or_update_seat('verified', True, 50, self.partner)
        _range = RangeFactory(products=[seat, ])
        prepare_voucher(code=COUPON_CODE, _range=_range)

        course_url = get_lms_url('api/courses/v1/courses/{}/'.format(course.id))
        httpretty.register_uri(httpretty.GET, course_url, status=404, content_type=CONTENT_TYPE)

        response = self.client.get(self.path_with_code)
        response_text = (
            'Could not get course information. '
            '[Client Error 404: http://127.0.0.1:8000/api/courses/v1/courses/{}/]'
        ).format(course.id)
        self.assertEqual(response.context['error'], _(response_text))
示例#23
0
    def setUp(self):
        super(CheckoutPageTest, self).setUp()

        user = self.create_user(is_superuser=False)
        self.create_access_token(user)
        self.client.login(username=user.username, password=self.password)
        self.provider = 'ASU'
        self.price = 100
        self.credit_hours = 2
        self.eligibility_url = get_lms_url('/api/credit/v1/eligibility/')
        self.provider_url = get_lms_url('/api/credit/v1/providers/')
        self.course = CourseFactory(thumbnail_url='http://www.edx.org/course.jpg')

        self.provider_data = [
            {
                'enable_integration': False,
                'description': 'Arizona State University',
                'url': 'https://credit.example.com/',
                'status_url': 'https://credit.example.com/status',
                'thumbnail_url': 'http://edX/DemoX/asset/images_course_image.jpg',
                'fulfillment_instructions': 'Sample fulfilment requirement.',
                'display_name': 'Arizona State University',
                'id': 'ASU'
            }
        ]

        self.eligibilities = [
            {
                'deadline': '2016-10-28T09:56:44Z',
                'course_key': 'edx/cs01/2015'
            }
        ]
示例#24
0
    def test_multiple_providers(self):
        """ Verify offer contains information about credit providers. """
        course = CourseFactory()
        seat1 = course.create_or_update_seat(
            'credit', False, 100, partner=self.partner, credit_provider='test_provider_1'
        )
        seat2 = course.create_or_update_seat(
            'credit', False, 100, partner=self.partner, credit_provider='test_provider_2'
        )
        self.assertEqual(Product.objects.filter(parent=seat1.parent).count(), 2)

        __, request, voucher = self.prepare_get_offers_response(seats=[seat1, seat2], seat_type='credit')
        self.mock_eligibility_api(request, self.user, course.id)
        offers = VoucherViewSet().get_offers(request=request, voucher=voucher)['results']
        for offer in offers:
            self.assertTrue(offer['multiple_credit_providers'])
            self.assertIsNone(offer['credit_provider_price'])
示例#25
0
    def prepare_course_seat_and_enrollment_code(self, seat_type='verified', id_verification=False):
        """Helper function that creates a new course, enables enrollment codes and creates a new
        seat and enrollment code for it.

        Args:
            seat_type (str): Seat/certification type.
            is_verification (bool): Whether or not id verification is required for the seat.
        Returns:
            The newly created course, seat and enrollment code.
        """
        course = CourseFactory()
        toggle_switch(ENROLLMENT_CODE_SWITCH, True)
        self.site.siteconfiguration.enable_enrollment_codes = True
        self.site.siteconfiguration.save()
        seat = course.create_or_update_seat(seat_type, id_verification, 10, self.partner, create_enrollment_code=True)
        enrollment_code = Product.objects.get(product_class__name=ENROLLMENT_CODE_PRODUCT_CLASS_NAME)
        return course, seat, enrollment_code
示例#26
0
    def prepare_order(self, seat_type, credit_provider_id=None):
        """
        Prepares order for a post-checkout test.

        Args:
            seat_type (str): Course seat type
            credit_provider_id (str): Credit provider associated with the course seat.

        Returns:
            Order
        """
        course = CourseFactory()
        seat = course.create_or_update_seat(seat_type, False, 50, self.partner, credit_provider_id, None, 2)
        basket = BasketFactory(site=self.site)
        basket.add_product(seat, 1)
        order = factories.create_order(basket=basket, user=self.user)
        return order
示例#27
0
    def test_prepare_basket_enrollment_with_voucher(self):
        """Verify the basket does not contain a voucher if enrollment code is added to it."""
        course = CourseFactory()
        toggle_switch(ENROLLMENT_CODE_SWITCH, True)
        course.create_or_update_seat('verified', False, 10, self.partner, create_enrollment_code=True)
        enrollment_code = Product.objects.get(product_class__name=ENROLLMENT_CODE_PRODUCT_CLASS_NAME)
        voucher, product = prepare_voucher()

        basket = prepare_basket(self.request, product, voucher)
        self.assertIsNotNone(basket)
        self.assertEqual(basket.all_lines()[0].product, product)
        self.assertTrue(basket.contains_a_voucher)

        basket = prepare_basket(self.request, enrollment_code, voucher)
        self.assertIsNotNone(basket)
        self.assertEqual(basket.all_lines()[0].product, enrollment_code)
        self.assertFalse(basket.contains_a_voucher)
    def test_seat_products(self):
        """
        Verify the method returns a list containing purchasable course seats.

        These seats should be the child products.
        """
        # Create a new course and verify it has a parent product, but no children.
        course = CourseFactory()
        self.assertEqual(course.products.count(), 1)
        self.assertEqual(len(course.seat_products), 0)

        # Create the seat products
        seats = [course.create_or_update_seat('honor', False, 0, self.partner),
                 course.create_or_update_seat('verified', True, 50, self.partner)]
        self.assertEqual(course.products.count(), 3)

        # The property should return only the child seats.
        self.assertEqual(set(course.seat_products), set(seats))
    def test_create_or_update_seat_without_stale_seat_removal(self):
        """
        Verify that professional education seats are not deleted if remove_stale_modes flag is not set.
        """
        course = CourseFactory()
        course.create_or_update_seat('professional', False, 0, self.partner)
        self.assertEqual(course.products.count(), 2)

        course.create_or_update_seat('professional', True, 0, self.partner, remove_stale_modes=False)
        self.assertEqual(course.products.count(), 3)

        product_mode = course.products.all()[0]
        self.assertEqual(product_mode.attr.id_verification_required, True)
        self.assertEqual(product_mode.attr.certificate_type, 'professional')

        product_mode = course.products.all()[1]
        self.assertEqual(product_mode.attr.id_verification_required, False)
        self.assertEqual(product_mode.attr.certificate_type, 'professional')
 def setUp(self):
     super(LMSPublisherTests, self).setUp()
     self.course = CourseFactory(verification_deadline=datetime.datetime.now() + datetime.timedelta(days=7))
     self.course.create_or_update_seat('honor', False, 0, self.partner)
     self.course.create_or_update_seat('verified', True, 50, self.partner)
     self.publisher = LMSPublisher()
     self.error_message = u'Failed to publish commerce data for {course_id} to LMS.'.format(
         course_id=self.course.id
     )
示例#31
0
    def test_track_completed_enrollment_order(self):
        """ Make sure we are sending GA events for Enrollment Code orders """
        with mock.patch(
                'ecommerce.extensions.checkout.signals.track_segment_event'
        ) as mock_track:

            course = CourseFactory(partner=self.partner)
            course.create_or_update_seat('verified',
                                         True,
                                         50,
                                         create_enrollment_code=True)
            enrollment_code = Product.objects.get(
                product_class__name=ENROLLMENT_CODE_PRODUCT_CLASS_NAME)

            basket = factories.BasketFactory(owner=self.user, site=self.site)
            basket.add_product(enrollment_code)

            order = factories.create_order(basket=basket, user=self.user)
            track_completed_order(None, order)
            assert mock_track.called
示例#32
0
    def test_successful_order_for_bulk_purchase(self):
        """
        Verify the view redirects to the Receipt page when the Order has been
        successfully placed for bulk purchase and also that the order is linked
        to the provided business client.
        """
        toggle_switch(ENROLLMENT_CODE_SWITCH, True)

        course = CourseFactory()
        course.create_or_update_seat('verified',
                                     True,
                                     50,
                                     create_enrollment_code=True)
        enrollment_code = Product.objects.get(
            product_class__name=ENROLLMENT_CODE_PRODUCT_CLASS_NAME)
        self.basket = create_basket(owner=self.user, site=self.site)
        self.basket.add_product(enrollment_code, quantity=1)

        # The basket should not have an associated order if no payment was made.
        self.assertFalse(Order.objects.filter(basket=self.basket).exists())

        request_data = self.generate_notification(
            self.basket,
            billing_address=self.billing_address,
        )
        request_data.update({'organization': 'Dummy Business Client'})
        request_data.update({PURCHASER_BEHALF_ATTRIBUTE: "False"})
        # Manually add organization and purchaser attributes on the basket for testing
        basket_add_organization_attribute(self.basket, request_data)

        response = self.client.post(self.path, request_data)
        self.assertTrue(Order.objects.filter(basket=self.basket).exists())
        self.assertEqual(response.status_code, 302)

        # Now verify that a new business client has been created and current
        # order is now linked with that client through Invoice model.
        order = Order.objects.filter(basket=self.basket).first()
        business_client = BusinessClient.objects.get(
            name=request_data['organization'])
        assert Invoice.objects.get(
            order=order).business_client == business_client
示例#33
0
    def setUp(self):
        super(UtilTests, self).setUp()

        self.user = self.create_user(full_name="Tešt Ušer", is_staff=True)
        self.client.login(username=self.user.username, password=self.password)

        self.course = CourseFactory(id='course-v1:test-org+course+run')
        self.verified_seat = self.course.create_or_update_seat(
            'verified', False, 100, self.partner)

        self.catalog = Catalog.objects.create(partner=self.partner)

        self.stock_record = StockRecord.objects.filter(
            product=self.verified_seat).first()
        self.seat_price = self.stock_record.price_excl_tax
        self.catalog.stock_records.add(self.stock_record)

        self.coupon = self.create_coupon(title='Tešt product',
                                         catalog=self.catalog,
                                         note='Tešt note',
                                         quantity=1,
                                         max_uses=1,
                                         voucher_type=Voucher.MULTI_USE)
        self.coupon.history.all().update(history_user=self.user)
        self.coupon_vouchers = CouponVouchers.objects.filter(
            coupon=self.coupon)

        self.data = {
            'benefit_type': Benefit.PERCENTAGE,
            'benefit_value': 100.00,
            'catalog': self.catalog,
            'coupon': self.coupon,
            'end_datetime':
            datetime.datetime.now() + datetime.timedelta(days=1),
            'enterprise_customer': None,
            'name': "Test voucher",
            'quantity': 10,
            'start_datetime':
            datetime.datetime.now() - datetime.timedelta(days=1),
            'voucher_type': Voucher.SINGLE_USE
        }
示例#34
0
    def test_execution_for_bulk_purchase(self):
        """
        Verify redirection to LMS receipt page after attempted payment
        execution if the Otto receipt page is disabled for bulk purchase and
        also that the order is linked to the provided business client..
        """
        toggle_switch(ENROLLMENT_CODE_SWITCH, True)
        self.mock_oauth2_response()

        course = CourseFactory()
        course.create_or_update_seat('verified', True, 50, self.partner, create_enrollment_code=True)
        self.basket = create_basket(owner=factories.UserFactory(), site=self.site)
        enrollment_code = Product.objects.get(product_class__name=ENROLLMENT_CODE_PRODUCT_CLASS_NAME)
        factories.create_stockrecord(enrollment_code, num_in_stock=2, price_excl_tax='10.00')
        self.basket.add_product(enrollment_code, quantity=1)

        # Create a payment record the view can use to retrieve a basket
        self.mock_payment_creation_response(self.basket)
        self.processor.get_transaction_parameters(self.basket, request=self.request)
        self.mock_payment_execution_response(self.basket)
        self.mock_payment_creation_response(self.basket, find=True)

        # Manually add organization attribute on the basket for testing
        self.RETURN_DATA.update({'organization': 'Dummy Business Client'})
        basket_add_organization_attribute(self.basket, self.RETURN_DATA)

        response = self.client.get(reverse('paypal:execute'), self.RETURN_DATA)
        self.assertRedirects(
            response,
            get_receipt_page_url(
                order_number=self.basket.order_number,
                site_configuration=self.basket.site.siteconfiguration
            ),
            fetch_redirect_response=False
        )

        # Now verify that a new business client has been created and current
        # order is now linked with that client through Invoice model.
        order = Order.objects.filter(basket=self.basket).first()
        business_client = BusinessClient.objects.get(name=self.RETURN_DATA['organization'])
        assert Invoice.objects.get(order=order).business_client == business_client
示例#35
0
    def test_convert_course(self, initial_cert_type, direction, new_cert_type):
        """Verify that an honor course can be converted to audit correctly."""
        course = CourseFactory()
        seat_to_convert = course.create_or_update_seat(initial_cert_type,
                                                       False, 0, self.partner)
        stock_record = StockRecord.objects.get(product=seat_to_convert)
        order_line = OrderLineFactory(stockrecord=stock_record,
                                      product=seat_to_convert)

        old_stock_record_sku = stock_record.partner_sku
        old_order_line_sku = order_line.partner_sku

        # Mock the LMS call
        with mock.patch.object(LMSPublisher, 'publish') as mock_publish:
            mock_publish.return_value = True
            call_command('convert_course',
                         course.id,
                         access_token=ACCESS_TOKEN,
                         commit=True,
                         direction=direction,
                         partner=self.partner.code)

        # Calling refresh_from_db doesn't seem to update the product's attributes
        seat_to_convert = Product.objects.get(pk=seat_to_convert.pk)
        stock_record.refresh_from_db()
        order_line.refresh_from_db()

        self.assertEqual(getattr(seat_to_convert.attr, 'certificate_type', ''),
                         new_cert_type)

        if new_cert_type == '':
            self.assertNotIn('with honor certificate', seat_to_convert.title)
        else:
            self.assertIn(' with honor certificate', seat_to_convert.title)

        # Verify that partner SKUs are correctly updated
        self.assertNotEqual(old_stock_record_sku, stock_record.partner_sku)
        self.assertNotEqual(old_order_line_sku, order_line.partner_sku)
        self.assertEqual(order_line.partner_sku, stock_record.partner_sku)

        self.assertTrue(mock_publish.called)
示例#36
0
    def test_prepare_basket_enrollment_with_voucher(self):
        """Verify the basket does not contain a voucher if enrollment code is added to it."""
        course = CourseFactory()
        course.create_or_update_seat('verified',
                                     False,
                                     10,
                                     self.partner,
                                     create_enrollment_code=True)
        enrollment_code = Product.objects.get(
            product_class__name=ENROLLMENT_CODE_PRODUCT_CLASS_NAME)
        voucher, product = prepare_voucher()

        basket = prepare_basket(self.request, [product], voucher)
        self.assertIsNotNone(basket)
        self.assertEqual(basket.all_lines()[0].product, product)
        self.assertTrue(basket.contains_a_voucher)

        basket = prepare_basket(self.request, [enrollment_code], voucher)
        self.assertIsNotNone(basket)
        self.assertEqual(basket.all_lines()[0].product, enrollment_code)
        self.assertFalse(basket.contains_a_voucher)
示例#37
0
    def test_enrolled_verified_student(self, mode, id_verification):
        """
        Verify the view return HTTP 400 if the student is already enrolled as verified student in the course
        (The Enrollment API call being used returns an active enrollment record in this case)
        """
        course = CourseFactory()
        self.mock_enrollment_api_success_enrolled(course.id, mode=mode)
        product = course.create_or_update_seat(mode, id_verification, 0,
                                               self.partner)
        stock_record = StockRecordFactory(product=product,
                                          partner=self.partner)
        catalog = Catalog.objects.create(partner=self.partner)
        catalog.stock_records.add(stock_record)

        url = '{path}?sku={sku}'.format(path=self.path,
                                        sku=stock_record.partner_sku)
        expected_content = 'You are already enrolled in {product}.'.format(
            product=product.course.name)
        response = self.client.get(url)
        self.assertEqual(response.status_code, 400)
        self.assertEqual(response.content, expected_content)
示例#38
0
    def setUp(self):
        super(BasketSummaryViewTests, self).setUp()
        self.user = self.create_user()
        self.client.login(username=self.user.username, password=self.password)
        self.course = CourseFactory(name='BasketSummaryTest')
        site_configuration = self.site.siteconfiguration

        site_configuration.payment_processors = DummyProcessor.NAME
        site_configuration.client_side_payment_processor = DummyProcessor.NAME
        site_configuration.save()

        toggle_switch(settings.PAYMENT_PROCESSOR_SWITCH_PREFIX + DummyProcessor.NAME, True)
    def test_handle_with_existing_course(self):
        """ The command should create the demo course with audit and verified seats,
        and publish that data to the LMS.
        """
        self.mock_access_token_response()

        course = CourseFactory(
            id='course-v1:edX+DemoX+Demo_Course',
            name='edX Demonstration Course',
            verification_deadline=datetime(year=2022, month=4, day=24, tzinfo=pytz.utc),
            partner=self.partner
        )

        seat_attrs = {'certificate_type': '', 'expires': None, 'price': 0.00, 'id_verification_required': False}
        course.create_or_update_seat(**seat_attrs)

        with mock.patch.object(Course, 'publish_to_lms', return_value=None) as mock_publish:
            call_command('create_demo_data', '--partner={}'.format(self.partner.short_code))
            mock_publish.assert_called_once_with()

        self.assert_seats_created('course-v1:edX+DemoX+Demo_Course', 'edX Demonstration Course', 149)
 def setUp(self):
     super(CreateRefundForOrdersTests, self).setUp()
     self.url = reverse('api:v2:manual-course-enrollment-order-list')
     self.user = self.create_user(is_staff=True)
     self.client.login(username=self.user.username, password=self.password)
     self.course = CourseFactory(id='course-v1:MAX+CX+Course',
                                 partner=self.partner)
     self.course_price = 50
     self.course.create_or_update_seat(certificate_type='verified',
                                       id_verification_required=True,
                                       price=self.course_price)
     self.course.create_or_update_seat(certificate_type='audit',
                                       id_verification_required=False,
                                       price=0)
     self.mock_access_token_response()
     self.mock_course_run_detail_endpoint(
         self.course,
         discovery_api_url=self.site.siteconfiguration.discovery_api_url,
         course_run_info={
             'course_uuid': '620a5ce5-6ff4-4b2b-bea1-a273c6920ae5'
         })
示例#41
0
    def test_omitting_expired_courses(self):
        """Verify professional courses who's enrollment end datetime have passed are omitted."""
        no_date_seat = CourseFactory().create_or_update_seat('professional', False, 100, partner=self.partner)
        valid_seat = CourseFactory().create_or_update_seat('professional', False, 100, partner=self.partner)
        expired_seat = CourseFactory().create_or_update_seat('professional', False, 100, partner=self.partner)

        course_discovery_results = [{
            'key': no_date_seat.attr.course_key,
            'enrollment_end': None,
        }, {
            'key': valid_seat.attr.course_key,
            'enrollment_end': str(now() + datetime.timedelta(days=1)),
        }, {
            'key': expired_seat.attr.course_key,
            'enrollment_end': str(now() - datetime.timedelta(days=1)),
        }]

        products, __ = VoucherViewSet().retrieve_course_objects(course_discovery_results, 'professional')
        self.assertIn(no_date_seat, products)
        self.assertIn(valid_seat, products)
        self.assertNotIn(expired_seat, products)
示例#42
0
    def setUp(self):
        super(EnterpriseAPITests, self).setUp()
        self.course_run = CourseFactory()
        self.learner = self.create_user(is_staff=True)
        self.client.login(username=self.learner.username, password=self.password)

        # Enable enterprise functionality
        toggle_switch(settings.ENABLE_ENTERPRISE_ON_RUNTIME_SWITCH, True)

        self.request.user = self.learner
        self.request.site = self.site
        self.request.strategy = DefaultStrategy()
示例#43
0
 def test_already_purchased_product(self):
     """
     Verify student can not place multiple orders for single course seat
     """
     course = CourseFactory()
     product = course.create_or_update_seat("Verified", True, 0,
                                            self.partner)
     stock_record = StockRecordFactory(product=product,
                                       partner=self.partner)
     catalog = Catalog.objects.create(partner=self.partner)
     catalog.stock_records.add(stock_record)
     sku = stock_record.partner_sku
     basket = factories.BasketFactory(owner=self.user, site=self.site)
     basket.add_product(product, 1)
     create_order(user=self.user, basket=basket)
     url = '{path}?sku={sku}'.format(path=self.path, sku=sku)
     expected_content = 'You have already purchased {course} seat.'.format(
         course=product.course.name)
     response = self.client.get(url)
     self.assertEqual(response.status_code, 200)
     self.assertEqual(response.context['error'], expected_content)
示例#44
0
    def setUp(self):
        super(EnrollmentFulfillmentModuleTests, self).setUp()

        self.user = factories.UserFactory()
        self.user.tracking_context = {
            'ga_client_id': 'test-client-id',
            'lms_user_id': 'test-user-id',
            'lms_ip': '127.0.0.1'
        }
        self.user.save()
        self.course = CourseFactory(id=self.course_id,
                                    name='Demo Course',
                                    partner=self.partner)

        self.seat = self.course.create_or_update_seat(self.certificate_type,
                                                      False, 100,
                                                      self.provider)

        basket = factories.BasketFactory(owner=self.user, site=self.site)
        basket.add_product(self.seat, 1)
        self.order = create_order(number=1, basket=basket, user=self.user)
示例#45
0
    def setUp(self):
        super(EntitlementsTests, self).setUp()
        self.learner = self.create_user(is_staff=True)
        self.client.login(username=self.learner.username,
                          password=self.password)

        # Enable enterprise functionality
        toggle_switch(settings.ENABLE_ENTERPRISE_ON_RUNTIME_SWITCH, True)

        self.course = CourseFactory(id='edx/Demo_Course/DemoX')
        course_seat = self.course.create_or_update_seat('verified',
                                                        False,
                                                        100,
                                                        partner=self.partner)
        stock_record = StockRecord.objects.get(product=course_seat)
        self.catalog = Catalog.objects.create(partner=self.partner)
        self.catalog.stock_records.add(stock_record)

        self.request.user = self.learner
        self.request.site = self.site
        self.request.strategy = DefaultStrategy()
示例#46
0
    def setUp(self):
        super(CouponReportCSVViewTest, self).setUp()

        self.user = self.create_user(full_name="Test User", is_staff=True)
        self.client.login(username=self.user.username, password=self.password)

        self.course = CourseFactory()
        self.verified_seat = self.course.create_or_update_seat('verified', False, 0, self.partner)

        self.stock_record = StockRecord.objects.filter(product=self.verified_seat).first()

        partner1 = PartnerFactory(name='Tester1')
        catalog1 = Catalog.objects.create(name="Test catalog 1", partner=partner1)
        catalog1.stock_records.add(self.stock_record)
        self.coupon1 = self.create_coupon(partner=partner1, catalog=catalog1)
        self.coupon1.history.all().update(history_user=self.user)
        partner2 = PartnerFactory(name='Tester2')
        catalog2 = Catalog.objects.create(name="Test catalog 2", partner=partner2)
        catalog2.stock_records.add(self.stock_record)
        self.coupon2 = self.create_coupon(partner=partner2, catalog=catalog2)
        self.coupon2.history.all().update(history_user=self.user)
示例#47
0
    def test_flush_with_product(self):
        """
        Verify the method fires 'Product Removed' Segment event with the correct information when basket is not empty
        """
        basket = create_basket(empty=True, site=self.site)
        course = CourseFactory()
        seat = course.create_or_update_seat('verified', True, 100, self.partner)
        basket.add_product(seat)

        properties = translate_basket_line_for_segment(basket.lines.first())
        user_tracking_id, ga_client_id, lms_ip = parse_tracking_context(basket.owner)
        context = {
            'ip': lms_ip,
            'Google Analytics': {
                'clientId': ga_client_id
            }
        }

        with mock.patch.object(Client, 'track') as mock_track:
            basket.flush()
            mock_track.assert_called_once_with(user_tracking_id, 'Product Removed', properties, context=context)
示例#48
0
    def prepare_course_seat_and_enrollment_code(self,
                                                seat_type='verified',
                                                id_verification=False):
        """Helper function that creates a new course, enables enrollment codes and creates a new
        seat and enrollment code for it.

        Args:
            seat_type (str): Seat/certification type.
            is_verification (bool): Whether or not id verification is required for the seat.
        Returns:
            The newly created course, seat and enrollment code.
        """
        course = CourseFactory()
        seat = course.create_or_update_seat(seat_type,
                                            id_verification,
                                            10,
                                            self.partner,
                                            create_enrollment_code=True)
        enrollment_code = Product.objects.get(
            product_class__name=ENROLLMENT_CODE_PRODUCT_CLASS_NAME)
        return course, seat, enrollment_code
示例#49
0
    def test_without_seats(self, direction):
        """Verify that the command fails when the course does not have the correct seat type."""
        course = CourseFactory()

        call_command('convert_course',
                     course.id,
                     access_token=ACCESS_TOKEN,
                     commit=True,
                     direction=direction,
                     partner=self.partner)

        self.assertEqual(len(course.seat_products), 0)
示例#50
0
    def test_save_creates_parent_seat(self):
        """ Verify the save method creates a parent seat if one does not exist. """
        course = CourseFactory(id='a/b/c',
                               name='Test Course',
                               partner=self.partner)
        self.assertEqual(course.products.count(), 1)

        parent = course.parent_seat_product
        self.assertEqual(parent.structure, Product.PARENT)
        self.assertEqual(parent.title, 'Seat in Test Course')
        self.assertEqual(parent.get_product_class(), self.seat_product_class)
        self.assertEqual(parent.attr.course_key, course.id)
示例#51
0
    def mock_program_detail_endpoint(self,
                                     program_uuid,
                                     discovery_api_url,
                                     empty=False,
                                     title='Test Program'):
        """ Mocks the program detail endpoint on the Catalog API.
        Args:
            program_uuid (uuid): UUID of the mocked program.

        Returns:
            dict: Mocked program data.
        """
        data = None
        if not empty:
            courses = []
            for i in range(1, 5):
                key = 'course-v1:test-org+course+' + str(i)
                course_runs = []
                for __ in range(1, 4):
                    course_run = CourseFactory()
                    course_run.create_or_update_seat('audit', False,
                                                     Decimal(0), self.partner)
                    course_run.create_or_update_seat('verified', True,
                                                     Decimal(100),
                                                     self.partner)

                    course_runs.append({
                        'key':
                        course_run.id,
                        'seats': [{
                            'type':
                            mode_for_product(seat),
                            'sku':
                            seat.stockrecords.get(
                                partner=self.partner).partner_sku,
                        } for seat in course_run.seat_products]
                    })

                courses.append({
                    'key': key,
                    'course_runs': course_runs,
                })

            program_uuid = str(program_uuid)
            data = {
                'uuid': program_uuid,
                'title': title,
                'type': 'MicroMockers',
                'courses': courses,
                'applicable_seat_types':
                ['verified', 'professional', 'credit'],
            }
        self.mock_access_token_response()
        httpretty.register_uri(method=httpretty.GET,
                               uri='{base}/programs/{uuid}/'.format(
                                   base=discovery_api_url.strip('/'),
                                   uuid=program_uuid),
                               body=json.dumps(data),
                               content_type='application/json')
        return data
示例#52
0
    def test_no_switch_link(self):
        """Verify response does not contain variables for the switch link if seat does not have an EC."""
        toggle_switch(ENROLLMENT_CODE_SWITCH, True)
        ec_course = CourseFactory()
        no_ec_course = CourseFactory()
        seat_without_ec = no_ec_course.create_or_update_seat(
            'verified', False, 10, self.partner)
        seat_with_ec = ec_course.create_or_update_seat(
            'verified', False, 10, self.partner, create_enrollment_code=True)
        self.create_basket_and_add_product(seat_without_ec)
        self.mock_dynamic_catalog_course_runs_api(course_run=no_ec_course)

        response = self.client.get(self.path)
        self.assertFalse(response.context['switch_link_text'])
        self.assertFalse(response.context['partner_sku'])

        # Enable enrollment codes
        self.site.siteconfiguration.enable_enrollment_codes = True
        self.site.siteconfiguration.save()

        Basket.objects.all().delete()
        self.create_basket_and_add_product(seat_with_ec)
        self.mock_dynamic_catalog_course_runs_api(course_run=ec_course)

        response = self.client.get(self.path)
        enrollment_code = Product.objects.get(
            product_class__name=ENROLLMENT_CODE_PRODUCT_CLASS_NAME)
        enrollment_code_stockrecord = StockRecord.objects.get(
            product=enrollment_code)
        self.assertTrue(response.context['switch_link_text'])
        self.assertEqual(response.context['partner_sku'],
                         enrollment_code_stockrecord.partner_sku)
示例#53
0
    def test_generate_coupon_report_for_query_coupon_with_multi_line_order(
            self):
        """
        Test that coupon report for a query coupon that was used on multi-line order
        contains ids from all courses in that order.
        """
        course1 = CourseFactory()
        course2 = CourseFactory()
        order = OrderFactory(number='TESTORDER')
        order.lines.add(
            OrderLineFactory(product=course1.create_or_update_seat(
                'verified', False, 101),
                             partner_sku=self.partner_sku))
        order.lines.add(
            OrderLineFactory(product=course2.create_or_update_seat(
                'verified', False, 110),
                             partner_sku=self.partner_sku))
        query_coupon = self.create_catalog_coupon(catalog_query='*:*')
        voucher = query_coupon.attr.coupon_vouchers.vouchers.first()
        voucher.record_usage(order, self.user)
        field_names, rows = generate_coupon_report(
            [query_coupon.attr.coupon_vouchers])

        expected_redemed_course_ids = '{}, {}'.format(course1.id, course2.id)
        self.assertEqual(rows[-1]['Redeemed For Course IDs'],
                         expected_redemed_course_ids)
        self.assertEqual(rows[-1].get('Redeemed For Course ID'), None)
        self.assertIn('Redeemed For Course ID', field_names)
        self.assertIn('Redeemed For Course IDs', field_names)
示例#54
0
    def test_create_seat_with_enrollment_code(self):
        """Verify an enrollment code product is created."""
        course = CourseFactory()
        seat_type = 'verified'
        price = 5
        toggle_switch(ENROLLMENT_CODE_SWITCH, True)
        course.create_or_update_seat(seat_type,
                                     True,
                                     price,
                                     self.partner,
                                     create_enrollment_code=True)

        enrollment_code = Product.objects.get(
            product_class__name=ENROLLMENT_CODE_PRODUCT_CLASS_NAME)
        self.assertEqual(enrollment_code.attr.course_key, course.id)
        self.assertEqual(enrollment_code.attr.seat_type, seat_type)

        # Second time should skip over the enrollment code creation logic but result in the same data
        course.create_or_update_seat(seat_type, True, price, self.partner)
        enrollment_code = Product.objects.get(
            product_class__name=ENROLLMENT_CODE_PRODUCT_CLASS_NAME)
        self.assertEqual(enrollment_code.attr.course_key, course.id)
        self.assertEqual(enrollment_code.attr.seat_type, seat_type)

        stock_record = StockRecord.objects.get(product=enrollment_code)
        self.assertEqual(stock_record.price_excl_tax, price)
        self.assertEqual(stock_record.price_currency,
                         settings.OSCAR_DEFAULT_CURRENCY)
        self.assertEqual(stock_record.partner, self.partner)
示例#55
0
    def test_create_or_update_seat(self):
        """ Verify the method creates or updates a seat Product. """
        course = CourseFactory(id='a/b/c',
                               name='Test Course',
                               partner=self.partner)

        # Test seat creation
        certificate_type = 'verified'
        id_verification_required = True
        price = 5
        course.create_or_update_seat(certificate_type,
                                     id_verification_required, price)

        # Two seats: one verified, the other the parent seat product
        self.assertEqual(course.products.count(), 2)
        seat = course.seat_products[0]
        self.assert_course_seat_valid(seat, course, certificate_type,
                                      id_verification_required, price)

        # Test seat update
        price = 10
        course.create_or_update_seat(certificate_type,
                                     id_verification_required,
                                     price,
                                     sku=seat.stockrecords.first().partner_sku)

        # Again, only two seats with one being the parent seat product.
        self.assertEqual(course.products.count(), 2)
        seat = course.seat_products[0]
        self.assert_course_seat_valid(seat, course, certificate_type,
                                      id_verification_required, price)
class ConvertHonorToAuditTests(CourseCatalogTestMixin, TestCase):
    def setUp(self):
        super(ConvertHonorToAuditTests, self).setUp()
        self.course = CourseFactory()
        self.honor_seat = self.course.create_or_update_seat(
            'honor', False, 0, self.partner)

    def test_honor_course(self):
        """ The command should delete the honor seat, and create a new audit seat. """
        # Mock the LMS call
        with mock.patch.object(LMSPublisher, 'publish') as mock_publish:
            mock_publish.return_value = True
            call_command('convert_honor_to_audit',
                         self.course.id,
                         access_token=ACCESS_TOKEN,
                         commit=True)

        # Verify honor seat deleted
        self.assertFalse(
            Product.objects.filter(id=self.honor_seat.id).exists())

        # Verify audit seat created
        audit_seats = [
            seat for seat in self.course.seat_products
            if getattr(seat.attr, 'certificate_type', '') == ''
        ]
        self.assertEqual(len(audit_seats), 1)

        # Verify data published to LMS
        self.assertTrue(mock_publish.called)

    def test_honor_course_without_commit(self):
        """ The command should raise an error and change no data if the commit flag is not set. """
        try:
            call_command('convert_honor_to_audit',
                         self.course.id,
                         access_token=ACCESS_TOKEN,
                         commit=False)
            self.fail(
                'An exception should be raised if the commit flag is not set.')
        except Exception:  # pylint: disable=broad-except
            pass

        # Verify honor seat still exists
        self.assertTrue(Product.objects.filter(id=self.honor_seat.id).exists())

        # Verify audit seat not in database
        audit_seats = [
            seat for seat in self.course.seat_products
            if getattr(seat.attr, 'certificate_type', '') == ''
        ]
        self.assertEqual(len(audit_seats), 0)
示例#57
0
    def test_prof_ed_stale_product_removal_with_orders(self):
        """
        Verify that professional education seats are never deleted if they have been purchased.
        """
        user = self.create_user()
        course = CourseFactory()
        professional_product_no_verification = course.create_or_update_seat('professional', False, 0, self.partner)
        self.assertEqual(course.products.count(), 2)

        basket = BasketFactory(owner=user)
        basket.add_product(professional_product_no_verification)
        create_order(basket=basket, user=user)
        course.create_or_update_seat('professional', True, 0, self.partner)
        self.assertEqual(course.products.count(), 3)

        product_mode = course.products.all()[0]
        self.assertEqual(product_mode.attr.id_verification_required, True)
        self.assertEqual(product_mode.attr.certificate_type, 'professional')

        product_mode = course.products.all()[1]
        self.assertEqual(product_mode.attr.id_verification_required, False)
        self.assertEqual(product_mode.attr.certificate_type, 'professional')
示例#58
0
    def test_more_than_one_product(self):
        """
        Test that we do not send email if basket contains more
        than one product
        """
        coupon = self.create_coupon()
        course = CourseFactory(partner=self.partner)
        seat = course.create_or_update_seat('verified', False, 50, None, None, 2)
        basket = factories.BasketFactory(owner=self.user, site=self.site)
        basket.add_product(seat)
        basket.add_product(coupon)
        order = create_order(basket=basket, user=self.user)

        with LogCapture(LOGGER_NAME) as logger:
            send_course_purchase_email(None, user=self.user, order=order)
            logger.check(
                (
                    LOGGER_NAME,
                    'INFO',
                    'Currently support receipt emails for order with one item.'
                )
            )
示例#59
0
    def test_translate_basket_line_for_segment(self):
        """ The method should return a dict formatted for Segment. """
        basket = create_basket(empty=True)
        basket.site = self.site
        basket.owner = factories.UserFactory()
        basket.save()
        course = CourseFactory()
        seat = course.create_or_update_seat('verified', True, 100,
                                            self.partner)
        basket.add_product(seat)
        line = basket.lines.first()
        expected = {
            'product_id': seat.stockrecords.first().partner_sku,
            'sku': 'verified',
            'name': course.id,
            'price': '100.00',
            'quantity': 1,
            'category': 'Seat',
        }
        self.assertEqual(translate_basket_line_for_segment(line), expected)

        # Products not associated with a Course should still be reported with the product's title instead of
        # the course ID.
        seat.course = None
        seat.save()

        # Refresh the basket
        basket.flush()
        basket.add_product(seat)
        line = basket.lines.first()

        expected['name'] = seat.title
        self.assertEqual(translate_basket_line_for_segment(line), expected)

        seat.course = None
        seat.save()
        course.delete()
        expected['name'] = seat.title
        self.assertEqual(translate_basket_line_for_segment(line), expected)
示例#60
0
    def test_course_information_error(self):
        """ Verify a response is returned when course information is not accessable. """
        course = CourseFactory()
        seat = course.create_or_update_seat('verified', True, 50, self.partner)
        _range = RangeFactory(products=[
            seat,
        ])
        prepare_voucher(code=COUPON_CODE, _range=_range)

        course_url = get_lms_url('api/courses/v1/courses/{}/'.format(
            course.id))
        httpretty.register_uri(httpretty.GET,
                               course_url,
                               status=404,
                               content_type=CONTENT_TYPE)

        response = self.client.get(self.path_with_code)
        response_text = (
            'Could not get course information. '
            '[Client Error 404: http://lms.testserver.fake/api/courses/v1/courses/{}/]'
        ).format(course.id)
        self.assertEqual(response.context['error'], _(response_text))