Ejemplo n.º 1
0
    def create_course_and_seats(self):
        # Delete existing Courses and products so we can retry creation.
        Course.objects.all().delete()

        # Create a Course.
        course = CourseFactory(
            id=self.course_id,
            name=self.course_name,
            verification_deadline=EXPIRES,
            partner=self.partner
        )

        # Create associated products.
        for product in self.data['products']:
            attrs = {'certificate_type': ''}
            attrs.update({attr['name']: attr['value'] for attr in product['attribute_values']})

            if product['product_class'] == COURSE_ENTITLEMENT_PRODUCT_CLASS_NAME:
                create_or_update_course_entitlement(
                    attrs['certificate_type'],
                    Decimal(product['price']),
                    self.partner,
                    self.course_uuid,
                    course.name,
                )
            else:
                attrs['expires'] = EXPIRES if product['expires'] else None
                attrs['price'] = Decimal(product['price'])

                course.create_or_update_seat(**attrs)
Ejemplo n.º 2
0
    def test_course_entitlement_update(self):
        """ Test course entitlement product update """

        partner = self.site.siteconfiguration.partner
        product = create_or_update_course_entitlement('verified', 100, self.partner, 'foo-bar', 'Foo Bar Entitlement')
        stock_record = StockRecord.objects.get(product=product, partner=self.partner)

        self.assertEqual(stock_record.price_excl_tax, 100)
        self.assertEqual(product.title, 'Course Entitlement for Foo Bar Entitlement')

        product = create_or_update_course_entitlement('verified', 200, partner, 'foo-bar', 'Foo Bar Entitlement')

        stock_record = StockRecord.objects.get(product=product, partner=self.partner)
        self.assertEqual(stock_record.price_excl_tax, 200)
Ejemplo n.º 3
0
    def save(partner, course, uuid, product):
        attrs = _flatten(product['attribute_values'])

        if not uuid:
            raise Exception(
                _(u"You need to provide a course UUID to create Course Entitlements."
                  ))

        # Extract arguments required for Seat creation, deserializing as necessary.
        certificate_type = attrs.get('certificate_type')
        price = Decimal(product['price'])

        create_or_update_course_entitlement(certificate_type, price, partner,
                                            uuid, course.name)
    def test_notify_purchaser_course_entielement(self, mock_task):
        """ Verify the notification is scheduled if the site has notifications enabled
        and the refund is for a course entitlement.
        """
        site_configuration = self.site.siteconfiguration
        site_configuration.send_refund_notifications = True

        user = UserFactory()

        course_entitlement = create_or_update_course_entitlement(
            'verified', 100, self.partner, '111-222-333-444',
            'Course Entitlement')
        basket = create_basket(site=self.site, owner=user, empty=True)
        basket.add_product(course_entitlement, 1)

        order = create_order(number=1, 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, 100)
        mock_task.assert_called_once_with(user.email,
                                          refund.id,
                                          amount,
                                          course_entitlement.title,
                                          order.number,
                                          order_url,
                                          site_code=self.partner.short_code)
Ejemplo n.º 5
0
    def test_get_course_info_from_catalog_cached(self):
        """
        Verify that get_course_info_from_catalog is cached

        We expect 2 calls to set_all_tiers in the get_course_info_from_catalog
        method due to:
            - the site_configuration api setup
            - the result being cached
        """
        self.mock_access_token_response()
        product = create_or_update_course_entitlement('verified', 100,
                                                      self.partner, 'foo-bar',
                                                      'Foo Bar Entitlement')
        self.mock_course_detail_endpoint(
            product,
            discovery_api_url=self.site_configuration.discovery_api_url)

        with patch.object(
                TieredCache, 'set_all_tiers',
                wraps=TieredCache.set_all_tiers) as mocked_set_all_tiers:
            mocked_set_all_tiers.assert_not_called()

            _ = get_course_info_from_catalog(self.request.site, product)
            self.assertEqual(mocked_set_all_tiers.call_count, 2)

            _ = get_course_info_from_catalog(self.request.site, product)
            self.assertEqual(mocked_set_all_tiers.call_count, 2)
Ejemplo n.º 6
0
    def test_get_course_run_info_from_catalog(self, course_run):
        """ Check to see if course info gets cached """
        self.mock_access_token_response()
        if course_run:
            course = CourseFactory(partner=self.partner)
            product = course.create_or_update_seat('verified', None, 100)
            key = CourseKey.from_string(product.attr.course_key)
            self.mock_course_run_detail_endpoint(
                course,
                discovery_api_url=self.site_configuration.discovery_api_url)
        else:
            product = create_or_update_course_entitlement(
                'verified', 100, self.partner, 'foo-bar',
                'Foo Bar Entitlement')
            key = product.attr.UUID
            self.mock_course_detail_endpoint(
                product,
                discovery_api_url=self.site_configuration.discovery_api_url)

        cache_key = u'courses_api_detail_{}{}'.format(key,
                                                      self.partner.short_code)
        cache_key = hashlib.md5(cache_key.encode('utf-8')).hexdigest()
        course_cached_response = TieredCache.get_cached_response(cache_key)
        self.assertFalse(course_cached_response.is_found)

        response = get_course_info_from_catalog(self.request.site, product)

        if course_run:
            self.assertEqual(response['title'], course.name)
        else:
            self.assertEqual(response['title'], product.title)

        course_cached_response = TieredCache.get_cached_response(cache_key)
        self.assertEqual(course_cached_response.value, response)
Ejemplo n.º 7
0
    def test_get_course_run_info_from_catalog(self, course_run):
        """ Check to see if course info gets cached """
        self.mock_access_token_response()
        if course_run:
            resource = "course_runs"
            course = CourseFactory(partner=self.partner)
            product = course.create_or_update_seat('verified', None, 100)
            key = CourseKey.from_string(product.attr.course_key)
            self.mock_course_run_detail_endpoint(
                course,
                discovery_api_url=self.site_configuration.discovery_api_url)
        else:
            resource = "courses"
            product = create_or_update_course_entitlement(
                'verified', 100, self.partner, 'foo-bar',
                'Foo Bar Entitlement')
            key = product.attr.UUID
            self.mock_course_detail_endpoint(
                discovery_api_url=self.site_configuration.discovery_api_url,
                course=product)

        cache_key = get_cache_key(site_domain=self.site.domain,
                                  resource="{}-{}".format(resource, key))
        course_cached_response = TieredCache.get_cached_response(cache_key)
        self.assertFalse(course_cached_response.is_found)

        response = get_course_info_from_catalog(self.request.site, product)

        if course_run:
            self.assertEqual(response['title'], course.name)
        else:
            self.assertEqual(response['title'], product.title)

        course_cached_response = TieredCache.get_cached_response(cache_key)
        self.assertEqual(course_cached_response.value, response)
Ejemplo n.º 8
0
    def create_order(self, user=None, credit=False, multiple_lines=False, free=False,
                     entitlement=False, status=ORDER.COMPLETE, id_verification_required=False):
        user = user or self.user
        basket = BasketFactory(owner=user, site=self.site)

        if credit:
            basket.add_product(self.credit_product)
        elif multiple_lines:
            basket.add_product(self.verified_product)
            basket.add_product(self.honor_product)
        elif free:
            basket.add_product(self.honor_product)
        elif entitlement:
            course_entitlement = create_or_update_course_entitlement(
                certificate_type='verified',
                price=100,
                partner=self.partner,
                UUID='111',
                title='Foo',
                id_verification_required=id_verification_required
            )
            basket.add_product(course_entitlement)
        else:
            basket.add_product(self.verified_product)

        order = create_order(basket=basket, user=user)
        order.status = status
        if entitlement:
            entitlement_option = Option.objects.get(code='course_entitlement')
            line = order.lines.first()
            line.attributes.create(option=entitlement_option, value='111')
        order.save()
        return order
Ejemplo n.º 9
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',
                                    partner=self.partner)
        self.verified_seat = self.course.create_or_update_seat(
            'verified', False, 100)

        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.entitlement = create_or_update_course_entitlement(
            'verified', 100, self.partner, 'foo-bar', 'Foo Bar Entitlement')
        self.entitlement_stock_record = StockRecord.objects.filter(
            product=self.entitlement).first()
        self.entitlement_catalog = Catalog.objects.create(partner=self.partner)
        self.entitlement_catalog.stock_records.add(
            self.entitlement_stock_record)
        self.entitlement_coupon = self.create_coupon(
            title='Tešt Entitlement product',
            catalog=self.entitlement_catalog,
            note='Tešt Entitlement note',
            quantity=1,
            max_uses=1,
            voucher_type=Voucher.MULTI_USE)
        self.entitlement_coupon_vouchers = CouponVouchers.objects.filter(
            coupon=self.entitlement_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,
            'enterprise_customer_catalog': None,
            'name': "Test voucher",
            'quantity': 10,
            'start_datetime':
            datetime.datetime.now() - datetime.timedelta(days=1),
            'voucher_type': Voucher.SINGLE_USE
        }
Ejemplo n.º 10
0
 def setUp(self):
     super(ManualCourseEnrollmentOrderViewSetTests, 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_uuid = '620a5ce5-6ff4-4b2b-bea1-a273c6920ae5'
     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.course_entitlement = create_or_update_course_entitlement(
         'verified', 100, self.partner, self.course_uuid, 'Course Entitlement'
     )
     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': self.course_uuid
         }
     )
     responses.start()
Ejemplo n.º 11
0
    def create(self, request, *args, **kwargs):
        """ Create a Product """
        data = request.data
        if data.get('product_class') == COURSE_ENTITLEMENT_PRODUCT_CLASS_NAME:
            product_creation_fields = {
                'certificate_type': data.get('certificate_type'),
                'price': data.get('price'),
                'partner': request.site.siteconfiguration.partner,
                'UUID': data.get('uuid'),
                'title': data.get('title'),
            }

            missing_values = [
                k for k, v in sorted(list(product_creation_fields.items()))
                if v is None
            ]
            if missing_values:
                return self.missing_values_response(missing_values)
            entitlement = create_or_update_course_entitlement(
                **product_creation_fields)

            entitlement_data = self.serializer_class(entitlement,
                                                     context={
                                                         'request': request
                                                     }).data
            return Response(entitlement_data, status=status.HTTP_201_CREATED)
        else:
            return self.invalid_product_response('POST')
Ejemplo n.º 12
0
    def test_order_details_entitlement_msg(self):
        """Verify the order details message is displayed for course entitlements."""

        product = create_or_update_course_entitlement(
            'verified', 100, self.partner, 'foo-bar', 'Foo Bar Entitlement')

        self.assert_order_details_in_context(product)
    def test_create_refund_for_duplicate_orders_only(self, commit):
        """
        Test that refund is generated for manual enrollment orders only if having some duplicate enrollments.
        """

        orders = self.create_manual_order()
        filename = 'orders_file.txt'
        self.create_orders_file(orders, filename)

        # create duplicate order having course_entitlement product
        order_with_duplicate = orders[0]
        order_without_duplicate = orders[1]

        course_uuid = FAKER.uuid4()  # pylint: disable=no-member
        order = Order.objects.get(number=order_with_duplicate['detail'])
        course_entitlement = create_or_update_course_entitlement(
            'verified', 100, order.partner, course_uuid, 'Course Entitlement'
        )
        basket = factories.BasketFactory(owner=order.user, site=order.site)
        basket.add_product(course_entitlement, 1)
        create_order(basket=basket, user=order.user)
        self.mock_access_token_response()
        self.mock_course_run_detail_endpoint(
            self.course,
            discovery_api_url=order.site.siteconfiguration.discovery_api_url,
            course_run_info={
                'course_uuid': course_uuid
            }
        )

        self.assertFalse(Refund.objects.exists())
        with LogCapture(LOGGER_NAME) as log_capture:
            params = ['create_refund_for_orders', '--order-numbers-file={}'.format(filename), '--refund-duplicate-only',
                      '--sleep-time=0.5']
            if not commit:
                params.append('--no-commit')
            call_command(*params)
            log_capture.check_present(
                (LOGGER_NAME, 'INFO', 'Sleeping for 0.5 second/seconds'),
            )
            log_capture.check_present(
                (
                    LOGGER_NAME,
                    'ERROR',
                    '[Ecommerce Order Refund]: Completed refund generation. 0 of 2 failed and 1 skipped.\n'
                    'Failed orders: \n'
                    'Skipped orders: {}\n'.format(order_without_duplicate['detail']),
                ),
            )
        if commit:
            self.assertEqual(Refund.objects.count(), 1)

            refund = Refund.objects.get(order=order)
            self.assert_refund_matches_order(refund, order)
            order = Order.objects.get(number=order_without_duplicate['detail'])
            self.assertFalse(order.refunds.exists())
        else:
            self.assertEqual(Refund.objects.count(), 0)
Ejemplo n.º 14
0
    def test_course_entitlement_creation(self):
        """ Test course entitlement product creation """

        product = create_or_update_course_entitlement(
            'verified', 100, self.partner, 'foo-bar', 'Foo Bar Entitlement')
        self.assertEqual(product.title, 'Course Entitlement for Foo Bar Entitlement')
        self.assertEqual(product.attr.UUID, 'foo-bar')

        stock_record = StockRecord.objects.get(product=product, partner=self.partner)
        self.assertEqual(stock_record.price_excl_tax, 100)
Ejemplo n.º 15
0
    def setUp(self):
        super(EnterpriseCustomerConditionTests, self).setUp()
        self.user = UserFactory()
        self.condition = factories.EnterpriseCustomerConditionFactory()

        self.test_product = ProductFactory(stockrecords__price_excl_tax=10, categories=[])
        self.course_run = CourseFactory(partner=self.partner)
        self.course_run.create_or_update_seat('verified', True, Decimal(100))

        self.entitlement = create_or_update_course_entitlement(
            'verified', 100, self.partner, 'edX-DemoX', 'edX Demo Entitlement'
        )
        self.entitlement_stock_record = StockRecord.objects.filter(product=self.entitlement).first()
        self.entitlement_catalog = Catalog.objects.create(partner=self.partner)
        self.entitlement_catalog.stock_records.add(self.entitlement_stock_record)
Ejemplo n.º 16
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)
Ejemplo n.º 17
0
 def setUp(self):
     super(EntitlementFulfillmentModuleTests, self).setUp()
     self.user = UserFactory()
     self.course_entitlement = create_or_update_course_entitlement(
         'verified', 100, self.partner, '111-222-333-444', 'Course Entitlement')
     basket = factories.BasketFactory(owner=self.user, site=self.site)
     basket.add_product(self.course_entitlement, 1)
     self.entitlement_option = Option.objects.get(name='Course Entitlement')
     self.order = create_order(number=1, basket=basket, user=self.user)
     self.logger_name = 'ecommerce.extensions.fulfillment.modules'
     self.return_data = {
         "user": "******",
         "course_uuid": "3b3123b8-d34b-44d8-9bbb-a12676e97123",
         "uuid": "111-222-333",
         "mode": "verified",
         "expired_at": "None"
     }
Ejemplo n.º 18
0
    def create(self, request, *args, **kwargs):
        product_class = request.data.get('product_class')
        if product_class == COURSE_ENTITLEMENT_PRODUCT_CLASS_NAME:

            product_creation_fields = {
                'partner':
                request.site.siteconfiguration.partner,
                'name':
                request.data.get('title'),
                'price':
                request.data.get('price'),
                'certificate_type':
                self._fetch_value_from_attribute_values('certificate_type'),
                'UUID':
                self._fetch_value_from_attribute_values('UUID')
            }

            for attribute_name, attribute_value in product_creation_fields.items(
            ):
                if attribute_value is None:
                    bad_rqst = 'Missing or bad value for: {}, required for Entitlement creation.'.format(
                        attribute_name)
                    return HttpResponseBadRequest(bad_rqst)

            entitlement = create_or_update_course_entitlement(
                product_creation_fields['certificate_type'],
                product_creation_fields['price'],
                product_creation_fields['partner'],
                product_creation_fields['UUID'],
                product_creation_fields['name'])

            data = self.serializer_class(entitlement,
                                         context={
                                             'request': request
                                         }).data
            return Response(data, status=status.HTTP_201_CREATED)
        else:
            bad_rqst = "Product API only supports POST for {} products".format(
                COURSE_ENTITLEMENT_PRODUCT_CLASS_NAME)
            return HttpResponseBadRequest(bad_rqst)
Ejemplo n.º 19
0
    def mock_program_detail_endpoint(self, program_uuid, discovery_api_url, empty=False, title='Test Program',
                                     include_entitlements=True):
        """ Mocks the program detail endpoint on the Catalog API.
        Args:
            program_uuid (uuid): UUID of the mocked program.

        Returns:
            dict: Mocked program data.
        """
        partner = PartnerFactory()
        data = None
        if not empty:
            courses = []
            for i in range(1, 5):
                uuid = '268afbfc-cc1e-415b-a5d8-c58d955bcfc' + str(i)
                entitlement = create_or_update_course_entitlement('verified', 10, partner, uuid, uuid)
                entitlements = []
                if include_entitlements:
                    entitlements.append(
                        {
                            "mode": "verified",
                            "price": "10.00",
                            "currency": "USD",
                            "sku": entitlement.stockrecords.first().partner_sku
                        }
                    )
                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, 'uuid': uuid, 'course_runs': course_runs, 'entitlements': entitlements, })

            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