Exemplo n.º 1
0
 def setUp(self):
     super(DefaultStrategyTests, self).setUp()
     self.strategy = DefaultStrategy()
     course = CourseFactory(id='a/b/c',
                            name='Demo Course',
                            partner=self.partner)
     self.honor_seat = course.create_or_update_seat('honor', False, 0)
Exemplo n.º 2
0
class DefaultStrategyTests(CourseCatalogTestMixin, TestCase):
    def setUp(self):
        super(DefaultStrategyTests, self).setUp()
        self.strategy = DefaultStrategy()
        course = Course.objects.create(id='a/b/c', name='Demo Course')
        self.honor_seat = course.create_or_update_seat('honor', False, 0)

    def test_seat_class(self):
        """ Verify the property returns the course seat Product Class. """
        self.assertEqual(self.strategy.seat_class, self.seat_product_class)

    def test_availability_policy_not_expired(self):
        """ If the course seat's expiration date has not passed, the seat should be available for purchase. """
        product = self.honor_seat
        product.expires = None
        stock_record = product.stockrecords.first()
        actual = self.strategy.availability_policy(self.honor_seat, stock_record)
        self.assertIsInstance(actual, availability.Available)

        product.expires = pytz.utc.localize(datetime.datetime.max)
        actual = self.strategy.availability_policy(product, stock_record)
        self.assertIsInstance(actual, availability.Available)

    def test_availability_policy_expired(self):
        """ If the course seat's expiration date has passed, the seat should NOT be available for purchase. """
        product = self.honor_seat
        product.expires = pytz.utc.localize(datetime.datetime.min)
        stock_record = product.stockrecords.first()
        actual = self.strategy.availability_policy(product, stock_record)
        self.assertIsInstance(actual, availability.Unavailable)
Exemplo n.º 3
0
 def assert_expired_product_availability(self, is_staff, available):
     request = RequestFactory()
     request.user = self.create_user(is_staff=is_staff)
     strategy = DefaultStrategy(request)
     product = self.honor_seat
     product.expires = pytz.utc.localize(datetime.datetime.min)
     stock_record = product.stockrecords.first()
     actual = strategy.availability_policy(product, stock_record)
     self.assertIsInstance(actual, available)
Exemplo n.º 4
0
 def assert_expired_product_availability(self, is_staff, available):
     request = RequestFactory()
     request.user = self.create_user(is_staff=is_staff)
     strategy = DefaultStrategy(request)
     product = self.honor_seat
     product.expires = pytz.utc.localize(datetime.datetime.min)
     stock_record = product.stockrecords.first()
     actual = strategy.availability_policy(product, stock_record)
     self.assertIsInstance(actual, available)
Exemplo n.º 5
0
class DefaultStrategyTests(DiscoveryTestMixin, TestCase):
    def setUp(self):
        super(DefaultStrategyTests, self).setUp()
        self.strategy = DefaultStrategy()
        course = CourseFactory(id='a/b/c',
                               name='Demo Course',
                               partner=self.partner)
        self.honor_seat = course.create_or_update_seat('honor', False, 0)

    def test_seat_class(self):
        """ Verify the property returns the course seat Product Class. """
        self.assertEqual(self.strategy.seat_class, self.seat_product_class)

    def test_availability_policy_not_expired(self):
        """ If the course seat's expiration date has not passed, the seat should be available for purchase. """
        product = self.honor_seat
        product.expires = None
        stock_record = product.stockrecords.first()
        actual = self.strategy.availability_policy(self.honor_seat,
                                                   stock_record)
        self.assertIsInstance(actual, availability.Available)

        product.expires = pytz.utc.localize(datetime.datetime.max)
        actual = self.strategy.availability_policy(product, stock_record)
        self.assertIsInstance(actual, availability.Available)

    def test_availability_policy_expired(self):
        """ If the course seat's expiration date has passed, the seat should NOT be available for purchase. """
        product = self.honor_seat
        product.expires = pytz.utc.localize(datetime.datetime.min)
        stock_record = product.stockrecords.first()
        actual = self.strategy.availability_policy(product, stock_record)
        self.assertIsInstance(actual, availability.Unavailable)

    @ddt.unpack
    @ddt.data(
        (True, availability.Available),
        (False, availability.Unavailable),
    )
    def test_expired_seats_availability_for_users(self, is_staff, available):
        """ A product is unavailable for students if the current date
        is beyond the product's expiration date. But for Admin products
        are always available.
        """
        self.assert_expired_product_availability(is_staff, available)

    def assert_expired_product_availability(self, is_staff, available):
        request = RequestFactory()
        request.user = self.create_user(is_staff=is_staff)
        strategy = DefaultStrategy(request)
        product = self.honor_seat
        product.expires = pytz.utc.localize(datetime.datetime.min)
        stock_record = product.stockrecords.first()
        actual = strategy.availability_policy(product, stock_record)
        self.assertIsInstance(actual, available)
Exemplo n.º 6
0
class DefaultStrategyTests(CourseCatalogTestMixin, UserMixin, PartnerMixin, TestCase):
    def setUp(self):
        super(DefaultStrategyTests, self).setUp()
        self.strategy = DefaultStrategy()
        course = Course.objects.create(id='a/b/c', name='Demo Course')
        partner = self.create_partner('edx')
        self.honor_seat = course.create_or_update_seat('honor', False, 0, partner)

    def test_seat_class(self):
        """ Verify the property returns the course seat Product Class. """
        self.assertEqual(self.strategy.seat_class, self.seat_product_class)

    def test_availability_policy_not_expired(self):
        """ If the course seat's expiration date has not passed, the seat should be available for purchase. """
        product = self.honor_seat
        product.expires = None
        stock_record = product.stockrecords.first()
        actual = self.strategy.availability_policy(self.honor_seat, stock_record)
        self.assertIsInstance(actual, availability.Available)

        product.expires = pytz.utc.localize(datetime.datetime.max)
        actual = self.strategy.availability_policy(product, stock_record)
        self.assertIsInstance(actual, availability.Available)

    def test_availability_policy_expired(self):
        """ If the course seat's expiration date has passed, the seat should NOT be available for purchase. """
        product = self.honor_seat
        product.expires = pytz.utc.localize(datetime.datetime.min)
        stock_record = product.stockrecords.first()
        actual = self.strategy.availability_policy(product, stock_record)
        self.assertIsInstance(actual, availability.Unavailable)

    @ddt.unpack
    @ddt.data(
        (True, availability.Available),
        (False, availability.Unavailable),
    )
    def test_expired_seats_availability_for_users(self, is_staff, available):
        """ A product is unavailable for students if the current date
        is beyond the product's expiration date. But for Admin products
        are always available.
        """
        self.assert_expired_product_availability(is_staff, available)

    def assert_expired_product_availability(self, is_staff, available):
        request = RequestFactory()
        request.user = self.create_user(is_staff=is_staff)
        strategy = DefaultStrategy(request)
        product = self.honor_seat
        product.expires = pytz.utc.localize(datetime.datetime.min)
        stock_record = product.stockrecords.first()
        actual = strategy.availability_policy(product, stock_record)
        self.assertIsInstance(actual, available)
Exemplo n.º 7
0
    def test_get_enterprise_customer_from_enterprise_offer(self, discount_value):
        """
        Verify that "get_enterprise_customer_from_enterprise_offer" returns `None` if expected conditions are not met.
        """
        course = CourseFactory(name='EnterpriseConsentErrorTest', partner=PartnerFactory())
        product = course.create_or_update_seat('verified', False, 50)

        benefit = EnterprisePercentageDiscountBenefitFactory(value=discount_value)
        offer = EnterpriseOfferFactory(benefit=benefit)
        # set wrong priority to invalidate the condition in util
        offer.priority = 111

        self.mock_enterprise_learner_api(
            learner_id=self.learner.id,
            enterprise_customer_uuid=str(offer.condition.enterprise_customer_uuid),
            course_run_id=course.id,
        )

        self.mock_catalog_contains_course_runs(
            [course.id],
            str(offer.condition.enterprise_customer_uuid),
            enterprise_customer_catalog_uuid=str(offer.condition.enterprise_customer_catalog_uuid),
            contains_content=True,
        )

        basket = BasketFactory(site=self.site, owner=self.create_user())
        basket.add_product(product)
        basket.strategy = DefaultStrategy()
        Applicator().apply_offers(basket, [offer])

        self.assertIsNone(get_enterprise_customer_from_enterprise_offer(basket))
Exemplo n.º 8
0
    def test_offer(self):
        # Our offer is for 100%, so all lines should end up with a price of 0.
        offer = factories.ProgramOfferFactory(benefit=factories.PercentageDiscountBenefitWithoutRangeFactory(value=100))
        basket = factories.BasketFactory(site=self.site, owner=self.create_user())

        program_uuid = offer.condition.program_uuid
        program = self.mock_program_detail_endpoint(program_uuid, self.site_configuration.discovery_api_url)

        # Add one course run seat from each course to the basket.
        for course in program['courses']:
            course_run = Course.objects.get(id=course['course_runs'][0]['key'])
            for seat in course_run.seat_products:
                if seat.attr.id_verification_required:
                    basket.add_product(seat)

        # No discounts should be applied, and each line should have a price of 100.00.
        self.assertEqual(len(basket.offer_applications), 0)
        self.assertEqual(basket.total_discount, 0)
        for line in basket.all_lines():
            self.assertEqual(line.line_price_incl_tax_incl_discounts, Decimal(100))

        # Apply the offers as Oscar will in a request
        basket.strategy = DefaultStrategy()
        Applicator().apply(basket, basket.owner)

        # Our discount should be applied, and each line should have a price of 0
        lines = basket.all_lines()
        self.assertEqual(len(basket.offer_applications), 1)
        self.assertEqual(basket.total_discount, Decimal(100) * len(lines))
        for line in lines:
            self.assertEqual(line.line_price_incl_tax_incl_discounts, 0)
Exemplo n.º 9
0
    def prepare_get_offers_response(self,
                                    quantity=1,
                                    seat_type='verified',
                                    seats=None):
        """Helper method for creating response the voucher offers endpoint.

        Args:
            quantity (int): Number of course runs

        Returns:
            The products, request and vouchers created.
        """
        course_run_info = {
            'count': quantity,
            'next': 'path/to/the/next/page',
            'results': []
        }
        products = []
        new_range, __ = Range.objects.get_or_create(
            catalog_query='*:*', course_seat_types=seat_type)
        if seats:
            for seat in seats:
                course_run_info['results'].append({
                    'image': {
                        'src': 'path/to/the/course/image'
                    },
                    'key': seat.course_id,
                    'start': '2016-05-01T00:00:00Z',
                    'title': seat.title,
                    'enrollment_end': None
                })
                new_range.add_product(seat)
        else:
            for _ in range(quantity):
                course, seat = self.create_course_and_seat(seat_type=seat_type)
                course_run_info['results'].append({
                    'image': {
                        'src': 'path/to/the/course/image'
                    },
                    'key': course.id,
                    'start': '2016-05-01T00:00:00Z',
                    'title': course.name,
                    'enrollment_end': None
                })
                new_range.add_product(seat)
                products.append(seat)

        self.mock_course_runs_endpoint(
            self.site_configuration.discovery_api_url,
            query='*:*',
            course_run_info=course_run_info)
        voucher, __ = prepare_voucher(_range=new_range)

        factory = APIRequestFactory()
        request = factory.get('/?code={}&page_size=6'.format(voucher.code))
        request.site = self.site
        request.user = self.user
        request.strategy = DefaultStrategy()

        return products, request, voucher
Exemplo n.º 10
0
    def test_offer(self):
        # Our offer is for 100%, so all lines should end up with a price of 0.
        offer = factories.ProgramOfferFactory(
            site=self.site,
            benefit=factories.PercentageDiscountBenefitWithoutRangeFactory(value=100)
        )
        basket = factories.BasketFactory(site=self.site, owner=self.create_user())

        program_uuid = offer.condition.program_uuid
        program = self.mock_program_detail_endpoint(program_uuid, self.site_configuration.discovery_api_url)
        self.mock_user_data(basket.owner.username)

        # Add one course run seat from each course to the basket.
        products = []
        for course in program['courses']:
            course_run = Course.objects.get(id=course['course_runs'][0]['key'])
            for seat in course_run.seat_products:
                if seat.attr.id_verification_required:
                    products.append(seat)
                    basket.add_product(seat)

        # No discounts should be applied, and each line should have a price of 100.00.
        self.assertEqual(len(basket.offer_applications), 0)
        self.assertEqual(basket.total_discount, 0)
        for line in basket.all_lines():
            self.assertEqual(line.line_price_incl_tax_incl_discounts, Decimal(100))

        # Apply the offers as Oscar will in a request
        basket.strategy = DefaultStrategy()
        Applicator().apply(basket, basket.owner)

        # Our discount should be applied, and each line should have a price of 0
        lines = basket.all_lines()
        self.assertEqual(len(basket.offer_applications), 1)
        self.assertEqual(basket.total_discount, Decimal(100) * len(lines))
        for line in lines:
            self.assertEqual(line.line_price_incl_tax_incl_discounts, 0)

        # Reset the basket and add a voucher.
        basket.reset_offer_applications()
        product_range = RangeFactory(products=products)
        voucher, __ = factories.prepare_voucher(_range=product_range, benefit_value=50)
        self.mock_account_api(self.request, basket.owner.username, data={'is_active': True})
        self.client.login(username=basket.owner.username, password=self.password)
        self.client.post(reverse('basket:vouchers-add'), data={'code': voucher.code})
        response = self.client.get(reverse('basket:summary'))
        basket = response.context['basket']

        # Verify that voucher-based offer takes precedence over program offer.
        actual_offer_discounts = [discount['offer'] for discount in basket.offer_discounts]
        actual_voucher_discounts = [discount['offer'] for discount in basket.voucher_discounts]
        self.assertEqual(actual_offer_discounts, [])
        self.assertEqual(actual_voucher_discounts, [voucher.offers.first()])
        lines = basket.all_lines()
        self.assertEqual(len(basket.offer_applications), 1)
        self.assertEqual(basket.total_discount, Decimal(50) * len(lines))
        for line in lines:
            self.assertEqual(line.line_price_incl_tax_incl_discounts, 50)
Exemplo n.º 11
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()
Exemplo n.º 12
0
    def test_omitting_unavailable_seats(self):
        """ Verify an unavailable seat is omitted from offer page results. """
        course1, seat1 = self.create_course_and_seat()
        course2, seat2 = self.create_course_and_seat()
        course_run_info = {
            'count':
            2,
            'next':
            'path/to/the/next/page',
            'results': [{
                'key': course1.id,
                'title': course1.name,
                'start': '2016-05-01T00:00:00Z',
                'image': {
                    'src': 'path/to/the/course/image'
                }
            }, {
                'key': course2.id,
                'title': course2.name,
                'start': '2016-05-01T00:00:00Z',
                'image': {
                    'src': 'path/to/the/course/image'
                }
            }]
        }

        self.mock_dynamic_catalog_course_runs_api(
            query='*:*', course_run_info=course_run_info)
        new_range, __ = Range.objects.get_or_create(catalog_query='*:*')
        new_range.add_product(seat1)
        new_range.add_product(seat2)
        voucher, __ = prepare_voucher(_range=new_range)
        voucher, products = get_voucher_and_products_from_code(voucher.code)
        factory = APIRequestFactory()
        request = factory.get('/?code={}&page_size=6'.format(voucher.code))
        request.site = self.site
        request.strategy = DefaultStrategy()
        offers = VoucherViewSet().get_offers(products=products,
                                             request=request,
                                             voucher=voucher)['results']
        self.assertEqual(len(offers), 2)

        products[1].expires = pytz.utc.localize(datetime.datetime.min)
        offers = VoucherViewSet().get_offers(products=products,
                                             request=request,
                                             voucher=voucher)['results']
        self.assertEqual(len(offers), 1)
Exemplo n.º 13
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()
Exemplo n.º 14
0
 def setUp(self):
     super(DefaultStrategyTests, self).setUp()
     self.strategy = DefaultStrategy()
     course = Course.objects.create(id='a/b/c', name='Demo Course')
     self.honor_seat = course.create_or_update_seat('honor', False, 0)
Exemplo n.º 15
0
    def handle(self, *args, **options):
        site_id = options.get('site_id')
        try:
            site = Site.objects.get(id=site_id)
        except Site.DoesNotExist:
            logger.exception('Site id %s does not exist', site_id)
            raise Exception

        try:
            site_configurations = SiteConfiguration.objects.get(site=site)
            configuration_helpers = site_configurations.edly_client_theme_branding_settings
            voucher_api_url = configuration_helpers.get(
                'LUMSXPAY_VOUCHER_API_URL')
            if not voucher_api_url:
                logger.exception(
                    'Cron Job of Update Payment Statuses is canceled due to no '
                    'LUMSXPAY_VOUCHER_API_URL in client theme branding')
                raise Exception
        except:
            logger.exception(
                'Site Configurations with side id %s does not exist', site_id)
            raise Exception

        try:
            unpaid_challan_baskets = BasketChallanVoucher.objects.filter(
                is_paid=False)
        except:
            logger.exception(
                'could not fetch the unpaid challan baskets from Database')
            raise Exception

        headers = {
            "Authorization":
            configuration_helpers.get('PAYMENT_AUTHORIZATION_KEY'),
            "Content-Type": "application/json"
        }

        paid_vouchers = []
        unpaid_vouchers = unpaid_challan_baskets.values_list('voucher_number',
                                                             flat=True)
        if unpaid_challan_baskets:
            for unpaid_vouchers_lst in list(
                    self.equal_divided_chunks(list(unpaid_vouchers),
                                              self.VOUCHERS_PER_REQUEST)):
                unpaid_vouchers_str = ','.join(unpaid_vouchers_lst)
                url = '{}/{}'.format(voucher_api_url, unpaid_vouchers_str)

                response = requests.get(url, headers=headers)
                if response.status_code == 200:
                    voucher_details = response.json()

                    voucher_data = voucher_details['data']
                    if not isinstance(voucher_details['data'], list):
                        voucher_data = [voucher_details['data']]

                    for voucher in voucher_data:
                        if voucher['paid_status'].lower() == 'paid':
                            paid_vouchers.append(voucher['voucher_id'])
                else:
                    logger.info('VOUCHER API doesnot return 200 OK')
                    return
        else:
            logger.info('No unpaid voucher found for update payment status')
            return

        if not paid_vouchers:
            logger.info('No voucher paid so exiting the job')
            return

        unpaid_basket_ids = unpaid_challan_baskets.filter(
            voucher_number__in=paid_vouchers).values_list('basket_id',
                                                          flat=True)

        paid_baskets = Basket.objects.filter(id__in=unpaid_basket_ids,
                                             status=Basket.OPEN)

        if not paid_baskets:
            logger.info(
                'ERROR: Basket corresponding to voucher does not exist')
            raise Exception

        for basket in paid_baskets:
            shipping_method = NoShippingRequired()
            shipping_charge = shipping_method.calculate(basket)
            basket.strategy = DefaultStrategy()
            order_total = OrderTotalCalculator().calculate(
                basket, shipping_charge)
            user = basket.owner
            billing_address = None
            request = RequestFactory()
            request.site = site
            request.user = user
            request.site.siteconfiguration = site_configurations
            set_thread_variable('request', request)
            order = EdxOrderPlacementMixin().handle_order_placement(
                order_number=basket.order_number,
                user=user,
                basket=basket,
                shipping_address=None,
                shipping_method=shipping_method,
                shipping_charge=shipping_charge,
                billing_address=billing_address,
                order_total=order_total,
                request=request)

            EdxOrderPlacementMixin().handle_post_order(order)
            challan_voucher_basket = BasketChallanVoucher.objects.filter(
                basket_id=basket.id)

            if len(challan_voucher_basket) > 1:
                logger.info(
                    'more than one basket exist with same id in challan table.'
                )
            elif challan_voucher_basket:
                challan_voucher_basket.update(is_paid=True)

        logger.info(
            'Successfully finished the cron job for updating the order payment'
        )
        return
Exemplo n.º 16
0
 def prepare_offers_listing_request(self, code):
     factory = APIRequestFactory()
     request = factory.get('/?code={}&page_size=6'.format(code))
     request.site = self.site
     request.strategy = DefaultStrategy()
     return request