Exemplo n.º 1
0
def update_voucher_offer(offer, benefit_value, benefit_type=None, max_uses=None, email_domains=None,
                         program_uuid=None, site=None):
    """
    Update voucher offer with new benefit value.

    Args:
        offer (Offer): Offer associated with a voucher.
        benefit_value (Decimal): Value of benefit associated with vouchers.
        benefit_type (str): Type of benefit associated with vouchers.

    Kwargs:
        max_uses (int): number of maximum global application number an offer can have.
        email_domains (str): a comma-separated string of email domains allowed to apply
                            this offer.
        program_uuid (str): Program UUID
        site (Site): Site for this offer

    Returns:
        Offer
    """

    return _get_or_create_offer(
        product_range=offer.benefit.range,
        benefit_value=benefit_value or offer.benefit.value,
        benefit_type=benefit_type or get_benefit_type(offer.benefit),
        offer_name=offer.name,
        max_uses=max_uses,
        email_domains=email_domains,
        program_uuid=program_uuid or offer.condition.program_uuid,
        site=site or offer.site,
    )
Exemplo n.º 2
0
def is_offer_max_discount_available(basket, offer):
    # no need to do anything if this is not an enterprise offer or `max_discount` is not set
    if offer.priority != OFFER_PRIORITY_ENTERPRISE or offer.max_discount is None:
        return True

    # get course price
    product = basket.lines.first().product
    seat = product.course.seat_products.get(id=product.id)
    stock_record = StockRecord.objects.get(product=seat, partner=product.course.partner)
    course_price = stock_record.price_excl_tax

    # calculate discount value that will be covered by the offer
    benefit_type = get_benefit_type(offer.benefit)
    benefit_value = offer.benefit.value
    if benefit_type == Benefit.PERCENTAGE:
        discount_value = get_discount_value(float(offer.benefit.value), float(course_price))
        discount_value = Decimal(discount_value)
    else:  # Benefit.FIXED
        # There is a possibility that the discount value could be greater than the course price
        # ie, discount value is $100, course price is $75, in this case the full price of the course will be covered
        # and learner will owe $0 to checkout.
        if benefit_value > course_price:
            discount_value = course_price
        else:
            discount_value = benefit_value

    # check if offer has discount available
    new_total_discount = discount_value + offer.total_discount
    if new_total_discount <= offer.max_discount:
        return True

    return False
Exemplo n.º 3
0
def update_voucher_with_enterprise_offer(offer, benefit_value, enterprise_customer, benefit_type=None,
                                         max_uses=None, email_domains=None, enterprise_catalog=None, site=None):
    """
    Update voucher with enteprise offer.

    Args:
        offer (Offer): Offer associated with a voucher.
        benefit_value (Decimal): Value of benefit associated with vouchers.
        benefit_type (str): Type of benefit associated with vouchers.
        coupon (Product): The coupon whos offer(s) is updated.
        enterprise_customer (str): The uuid of the enterprise customer.

    Kwargs:
        max_uses (int): number of maximum global application number an offer can have.
        email_domains (str): a comma-separated string of email domains allowed to apply
                            this offer.
        enterprise_catalog (str): Enterprise Catalog UUID
        site (Site): Site for this offer

    Returns:
        Offer
    """
    return get_or_create_enterprise_offer(
        benefit_value=benefit_value or offer.benefit.value,
        benefit_type=benefit_type or get_benefit_type(offer.benefit),
        enterprise_customer=enterprise_customer or offer.condition.enterprise_customer_uuid,
        enterprise_customer_catalog=enterprise_catalog or offer.condition.enterprise_customer_catalog_uuid,
        offer_name=offer.name,
        max_uses=max_uses,
        email_domains=email_domains,
        site=site or offer.site,
    )
Exemplo n.º 4
0
 def test_get_offers_for_multiple_courses_voucher(self):
     """ Verify that the course offers data is returned for a multiple courses voucher. """
     self.mock_access_token_response()
     course, seat = self.create_course_and_seat()
     self.mock_course_runs_endpoint(
         self.site_configuration.discovery_api_url, query='*:*', course_run=course
     )
     new_range, __ = Range.objects.get_or_create(catalog_query='*:*', course_seat_types='verified')
     new_range.add_product(seat)
     voucher, __ = prepare_voucher(_range=new_range, benefit_value=10)
     benefit = voucher.offers.first().benefit
     request = self.prepare_offers_listing_request(voucher.code)
     offers = VoucherViewSet().get_offers(request=request, voucher=voucher)['results']
     first_offer = offers[0]
     self.assertEqual(len(offers), 1)
     self.assertDictEqual(first_offer, {
         'benefit': {
             'type': get_benefit_type(benefit),
             'value': benefit.value
         },
         'contains_verified': True,
         'course_start_date': '2016-05-01T00:00:00Z',
         'id': course.id,
         'image_url': 'path/to/the/course/image',
         'multiple_credit_providers': False,
         'organization': CourseKey.from_string(course.id).org,
         'credit_provider_price': None,
         'seat_type': seat.attr.certificate_type,
         'stockrecords': serializers.StockRecordSerializer(seat.stockrecords.first()).data,
         'title': course.name,
         'voucher_end_date': voucher.end_datetime,
     })
Exemplo n.º 5
0
 def test_get_offers_for_enterprise_catalog_voucher(self):
     """ Verify that the course offers data is returned for an enterprise catalog voucher. """
     Switch.objects.update_or_create(
         name=ENTERPRISE_OFFERS_FOR_COUPONS_SWITCH,
         defaults={'active': False})
     self.mock_access_token_response()
     course, seat = self.create_course_and_seat()
     enterprise_catalog_id = str(uuid4())
     self.mock_enterprise_catalog_course_endpoint(
         self.site_configuration.enterprise_api_url,
         enterprise_catalog_id,
         course_run=course)
     new_range, __ = Range.objects.get_or_create(
         catalog_query='*:*',
         course_seat_types='verified',
         enterprise_customer=str(uuid4()),
         enterprise_customer_catalog=enterprise_catalog_id,
     )
     new_range.add_product(seat)
     voucher, __ = prepare_voucher(_range=new_range, benefit_value=10)
     benefit = voucher.offers.first().benefit
     request = self.prepare_offers_listing_request(voucher.code)
     offers = VoucherViewSet().get_offers(request=request,
                                          voucher=voucher)['results']
     first_offer = offers[0]
     self.assertEqual(len(offers), 1)
     self.assertDictEqual(
         first_offer, {
             'benefit': {
                 'type': get_benefit_type(benefit),
                 'value': benefit.value
             },
             'contains_verified':
             True,
             'course_start_date':
             '2016-05-01T00:00:00Z',
             'id':
             course.id,
             'image_url':
             'path/to/the/course/image',
             'multiple_credit_providers':
             False,
             'organization':
             CourseKey.from_string(course.id).org,
             'credit_provider_price':
             None,
             'seat_type':
             course.type,
             'stockrecords':
             serializers.StockRecordSerializer(
                 seat.stockrecords.first()).data,
             'title':
             course.name,
             'voucher_end_date':
             voucher.end_datetime,
         })
Exemplo n.º 6
0
 def _add_offers(self, response):
     response['offers'] = [
         {
             'provider': offer.condition.enterprise_customer_name,
             'name': offer.name,
             'benefit_type': get_benefit_type(offer.benefit) if offer.benefit else None,
             'benefit_value': get_quantized_benefit_value(offer.benefit) if offer.benefit else None,
         }
         for offer in self.request.basket.applied_offers().values()
         if (offer.condition.enterprise_customer_name or
             (offer.condition.name and offer.offer_type == ConditionalOffer.SITE))
     ]
Exemplo n.º 7
0
 def _add_coupons(self, response, context):
     response['show_coupon_form'] = context['show_voucher_form']
     benefit = context['total_benefit_object']
     response['coupons'] = [
         {
             'id': voucher.id,
             'code': voucher.code,
             'benefit_type': get_benefit_type(benefit) if benefit else None,
             'benefit_value': get_quantized_benefit_value(benefit) if benefit else None,
         }
         for voucher in self.request.basket.vouchers.all()
         if response['show_coupon_form'] and self.request.basket.contains_a_voucher
     ]
Exemplo n.º 8
0
 def test_get_offers_for_enterprise_offer(self):
     """ Verify that the course offers data is returned for an enterprise catalog voucher. """
     self.mock_access_token_response()
     course, seat = self.create_course_and_seat()
     enterprise_customer_id = str(uuid4())
     enterprise_catalog_id = str(uuid4())
     self.mock_enterprise_catalog_course_endpoint(
         self.site_configuration.enterprise_api_url,
         enterprise_catalog_id,
         course_run=course)
     voucher = prepare_enterprise_voucher(
         benefit_value=10,
         enterprise_customer=enterprise_customer_id,
         enterprise_customer_catalog=enterprise_catalog_id)
     benefit = voucher.offers.first().benefit
     request = self.prepare_offers_listing_request(voucher.code)
     offers = VoucherViewSet().get_offers(request=request,
                                          voucher=voucher)['results']
     first_offer = offers[0]
     self.assertEqual(len(offers), 1)
     self.assertDictEqual(
         first_offer, {
             'benefit': {
                 'type': get_benefit_type(benefit),
                 'value': benefit.value
             },
             'contains_verified':
             True,
             'course_start_date':
             '2016-05-01T00:00:00Z',
             'id':
             course.id,
             'image_url':
             'path/to/the/course/image',
             'multiple_credit_providers':
             False,
             'organization':
             CourseKey.from_string(course.id).org,
             'credit_provider_price':
             None,
             'seat_type':
             seat.attr.certificate_type,
             'stockrecords':
             serializers.StockRecordSerializer(
                 seat.stockrecords.first()).data,
             'title':
             course.name,
             'voucher_end_date':
             voucher.end_datetime,
         })
Exemplo n.º 9
0
    def test_offers_api_endpoint_for_course_catalog_voucher(self):
        """
        Verify that the course offers data is returned for a course catalog voucher.
        """
        catalog_id = 1
        catalog_query = '*:*'

        self.mock_access_token_response()
        # Populate database for the test case.
        course, seat = self.create_course_and_seat()
        new_range, __ = Range.objects.get_or_create(course_catalog=catalog_id, course_seat_types='verified')
        new_range.add_product(seat)
        voucher, __ = prepare_voucher(_range=new_range, benefit_value=10)

        # Mock network calls
        self.mock_catalog_detail_endpoint(
            catalog_id=catalog_id, expected_query=catalog_query,
            discovery_api_url=self.site_configuration.discovery_api_url
        )
        self.mock_course_runs_endpoint(
            discovery_api_url=self.site_configuration.discovery_api_url, query=catalog_query, course_run=course
        )

        benefit = voucher.offers.first().benefit
        request = self.prepare_offers_listing_request(voucher.code)

        response = self.endpointView(request)
        # Verify that offers are returned when voucher is created using course catalog
        self.assertEqual(response.status_code, 200)
        self.assertListEqual(
            response.data['results'],
            [{
                'benefit': {
                    'type': get_benefit_type(benefit),
                    'value': benefit.value
                },
                'contains_verified': True,
                'course_start_date': '2016-05-01T00:00:00Z',
                'id': course.id,
                'image_url': 'path/to/the/course/image',
                'multiple_credit_providers': False,
                'organization': CourseKey.from_string(course.id).org,
                'credit_provider_price': None,
                'seat_type': seat.attr.certificate_type,
                'stockrecords': serializers.StockRecordSerializer(seat.stockrecords.first()).data,
                'title': course.name,
                'voucher_end_date': voucher.end_datetime,
            }],
        )
Exemplo n.º 10
0
    def test_get_offers_for_single_course_voucher(self):
        """ Verify that the course offers data is returned for a single course voucher. """
        self.mock_access_token_response()
        course, seat = self.create_course_and_seat()
        new_range = RangeFactory(products=[
            seat,
        ])
        voucher, __ = prepare_voucher(_range=new_range, benefit_value=10)
        benefit = voucher.offers.first().benefit
        request = self.prepare_offers_listing_request(voucher.code)
        self.mock_course_run_detail_endpoint(
            course,
            discovery_api_url=self.site_configuration.discovery_api_url)
        offers = VoucherViewSet().get_offers(request=request,
                                             voucher=voucher)['results']
        first_offer = offers[0]

        self.assertEqual(len(offers), 1)
        self.assertDictEqual(
            first_offer, {
                'benefit': {
                    'type': get_benefit_type(benefit),
                    'value': benefit.value
                },
                'contains_verified':
                True,
                'course_start_date':
                '2013-02-05T05:00:00Z',
                'id':
                course.id,
                'image_url':
                '/path/to/image.jpg',
                'multiple_credit_providers':
                False,
                'organization':
                CourseKey.from_string(course.id).org,
                'credit_provider_price':
                None,
                'seat_type':
                course.type,
                'stockrecords':
                serializers.StockRecordSerializer(
                    seat.stockrecords.first()).data,
                'title':
                course.name,
                'voucher_end_date':
                voucher.end_datetime,
            })
Exemplo n.º 11
0
    def test_get_course_offer_data(self):
        """ Verify that the course offers data is properly formatted. """
        benefit = BenefitFactory()
        course, seat = self.create_course_and_seat()
        course_info = {
            'start': '2016-05-01T00:00:00Z',
            'image': {
                'src': 'path/to/the/course/image'
            }
        }
        stock_record = seat.stockrecords.first()
        voucher = VoucherFactory()

        offer = VoucherViewSet().get_course_offer_data(
            benefit=benefit,
            course=course,
            course_info=course_info,
            credit_provider_price=None,
            multiple_credit_providers=False,
            is_verified=True,
            product=seat,
            stock_record=stock_record,
            voucher=voucher)

        self.assertDictEqual(
            offer, {
                'benefit': {
                    'type': get_benefit_type(benefit),
                    'value': benefit.value
                },
                'contains_verified': True,
                'course_start_date': course_info['start'],
                'id': course.id,
                'image_url': course_info['image']['src'],
                'multiple_credit_providers': False,
                'organization': CourseKey.from_string(course.id).org,
                'credit_provider_price': None,
                'seat_type': seat.attr.certificate_type,
                'stockrecords':
                serializers.StockRecordSerializer(stock_record).data,
                'title': course.name,
                'voucher_end_date': voucher.end_datetime,
            })
Exemplo n.º 12
0
def _get_basket_discount_value(basket, offer):
    """Calculate the discount value based on benefit type and value"""
    sum_basket_lines = basket.all_lines().aggregate(
        total=Sum('stockrecord__price_excl_tax'))['total'] or Decimal(0.0)
    # calculate discount value that will be covered by the offer
    benefit_type = get_benefit_type(offer.benefit)
    benefit_value = offer.benefit.value
    if benefit_type == Benefit.PERCENTAGE:
        discount_value = get_discount_value(float(offer.benefit.value),
                                            float(sum_basket_lines))
        discount_value = Decimal(discount_value)
    else:  # Benefit.FIXED
        # There is a possibility that the discount value could be greater than the sum of basket lines
        # ie, discount value is $100, basket lines are $75, in this case the full price of the basket lines
        # will be covered and learner will owe $0 to checkout.
        if benefit_value > sum_basket_lines:
            discount_value = sum_basket_lines
        else:
            discount_value = benefit_value
    return discount_value
Exemplo n.º 13
0
def _get_course_discount_value(basket, offer):
    """Calculate the discount value based on benefit type and value"""
    product = basket.lines.first().product
    seat = product.course.seat_products.get(id=product.id)
    stock_record = StockRecord.objects.get(product=seat,
                                           partner=product.course.partner)
    course_price = stock_record.price_excl_tax

    # calculate discount value that will be covered by the offer
    benefit_type = get_benefit_type(offer.benefit)
    benefit_value = offer.benefit.value
    if benefit_type == Benefit.PERCENTAGE:
        discount_value = get_discount_value(float(offer.benefit.value),
                                            float(course_price))
        discount_value = Decimal(discount_value)
    else:  # Benefit.FIXED
        # There is a possibility that the discount value could be greater than the course price
        # ie, discount value is $100, course price is $75, in this case the full price of the course will be covered
        # and learner will owe $0 to checkout.
        if benefit_value > course_price:
            discount_value = course_price
        else:
            discount_value = benefit_value
    return discount_value
Exemplo n.º 14
0
def _get_info_for_coupon_report(coupon, voucher):
    created_date = coupon.date_updated.strftime(
        "%b %d, %y") if coupon.date_updated else 'N/A'
    category_name = ProductCategory.objects.get(product=coupon).category.name

    try:
        note = coupon.attr.note
    except AttributeError:
        note = ''

    coupon_stockrecord = StockRecord.objects.get(product=coupon)
    invoiced_amount = currency(coupon_stockrecord.price_excl_tax)
    offer = voucher.best_offer
    offer_range = offer.condition.range
    program_uuid = offer.condition.program_uuid
    benefit = offer.benefit

    course_id = None
    seat_stockrecord = None
    course_organization = None
    catalog_query = None
    course_seat_types = None

    if program_uuid:
        course_id = None
    elif offer_range and offer_range.catalog:
        seat_stockrecord = offer_range.catalog.stock_records.first()
        course_id, course_organization = _get_course_id_and_organization(
            seat_stockrecord)
    elif offer_range and offer_range.catalog_query:
        catalog_query = offer_range.catalog_query
        course_id = None
        course_seat_types = offer_range.course_seat_types

    if course_id:
        price = currency(seat_stockrecord.price_excl_tax)
        discount_data = get_voucher_discount_info(
            benefit, seat_stockrecord.price_excl_tax)
        coupon_type, discount_percentage, discount_amount = _get_discount_info(
            discount_data)
    else:
        benefit_type = get_benefit_type(benefit)

        if benefit_type == Benefit.PERCENTAGE:
            coupon_type = _('Discount') if benefit.value < 100 else _(
                'Enrollment')
        else:
            coupon_type = None

        discount_percentage = _('{percentage} %').format(
            percentage=benefit.value
        ) if benefit_type == Benefit.PERCENTAGE else None
        discount_amount = None
        price = None

    coupon_data = {
        _('Code'): _('This row applies to all vouchers'),
        _('Category'): category_name,
        _('Coupon Expiry Date'): voucher.end_datetime.strftime("%b %d, %y"),
        _('Coupon Name'): voucher.name,
        _('Coupon Start Date'): voucher.start_datetime.strftime("%b %d, %y"),
        _('Coupon Type'): coupon_type,
        _('Create Date'): created_date,
        _('Discount Percentage'): discount_percentage,
        _('Discount Amount'): discount_amount,
        _('Email Domains'): offer.email_domains,
        _('Invoiced Amount'): invoiced_amount,
        _('Note'): note,
        _('Price'): price
    }

    if course_id:
        coupon_data[_('Course ID')] = course_id
        coupon_data[_('Organization')] = course_organization
    elif program_uuid:
        coupon_data[_('Program UUID')] = program_uuid
    else:
        coupon_data[_('Catalog Query')] = catalog_query
        coupon_data[_('Course Seat Types')] = course_seat_types

    return coupon_data
Exemplo n.º 15
0
def benefit_type(benefit):
    return get_benefit_type(benefit)