Commit dc8665f7 by Vedran Karačić Committed by GitHub

Merge pull request #811 from edx/vkaracic/SOL-1819

[SOL-1819] Multi offer coupon.
parents 39ef7b72 b897debc
...@@ -134,6 +134,25 @@ class CouponViewSetTest(CouponMixin, CourseCatalogTestMixin, TestCase): ...@@ -134,6 +134,25 @@ class CouponViewSetTest(CouponMixin, CourseCatalogTestMixin, TestCase):
category = ProductCategory.objects.get(product=coupon).category category = ProductCategory.objects.get(product=coupon).category
self.assertEqual(category, self.category) self.assertEqual(category, self.category)
def test_creating_multi_offer_coupon(self):
"""Test the creation of a multi-offer coupon."""
ordinary_max_uses = 1
ordinary_coupon = self.create_coupon(quantity=2, max_uses=ordinary_max_uses)
ordinary_coupon_vouchers = ordinary_coupon.attr.coupon_vouchers.vouchers.all()
self.assertEqual(
ordinary_coupon_vouchers[0].offers.first(),
ordinary_coupon_vouchers[1].offers.first()
)
self.assertEqual(ordinary_coupon_vouchers[0].offers.first().max_global_applications, ordinary_max_uses)
multi_offer_coupon = self.create_coupon(quantity=2, max_uses=2)
multi_offer_coupon_vouchers = multi_offer_coupon.attr.coupon_vouchers.vouchers.all()
first_offer = multi_offer_coupon_vouchers[0].offers.first()
second_offer = multi_offer_coupon_vouchers[1].offers.first()
self.assertNotEqual(first_offer, second_offer)
self.assertEqual(first_offer.max_global_applications, second_offer.max_global_applications)
def test_custom_code_string(self): def test_custom_code_string(self):
"""Test creating a coupon with custom voucher code.""" """Test creating a coupon with custom voucher code."""
self.coupon_data.update({ self.coupon_data.update({
......
...@@ -220,7 +220,9 @@ def generate_coupon_report(coupon_vouchers): ...@@ -220,7 +220,9 @@ def generate_coupon_report(coupon_vouchers):
return field_names, rows return field_names, rows
def _get_or_create_offer(product_range, benefit_type, benefit_value, coupon_id=None, max_uses=None): def _get_or_create_offer(
product_range, benefit_type, benefit_value, coupon_id=None, max_uses=None, offer_number=None
):
""" """
Return an offer for a catalog with condition and benefit. Return an offer for a catalog with condition and benefit.
...@@ -248,9 +250,8 @@ def _get_or_create_offer(product_range, benefit_type, benefit_value, coupon_id=N ...@@ -248,9 +250,8 @@ def _get_or_create_offer(product_range, benefit_type, benefit_value, coupon_id=N
) )
offer_name = "Coupon [{}]-{}-{}".format(coupon_id, offer_benefit.type, offer_benefit.value) offer_name = "Coupon [{}]-{}-{}".format(coupon_id, offer_benefit.type, offer_benefit.value)
if max_uses: if offer_number:
# Offer needs to be unique for each multi-use coupon. offer_name = "{} [{}]".format(offer_name, offer_number)
offer_name = "{} (Coupon [{}] - max_uses:{})".format(offer_name, coupon_id, max_uses)
offer, __ = ConditionalOffer.objects.get_or_create( offer, __ = ConditionalOffer.objects.get_or_create(
name=offer_name, name=offer_name,
...@@ -359,6 +360,7 @@ def create_vouchers( ...@@ -359,6 +360,7 @@ def create_vouchers(
""" """
logger.info("Creating [%d] vouchers product [%s]", quantity, coupon.id) logger.info("Creating [%d] vouchers product [%s]", quantity, coupon.id)
vouchers = [] vouchers = []
offers = []
if _range: if _range:
# Enrollment codes use a custom range. # Enrollment codes use a custom range.
...@@ -374,18 +376,28 @@ def create_vouchers( ...@@ -374,18 +376,28 @@ def create_vouchers(
course_seat_types=course_seat_types course_seat_types=course_seat_types
) )
offer = _get_or_create_offer( # In case of more than 1 multi-usage coupon, each voucher needs to have an individual
product_range=product_range, # offer because the usage is tied to the offer so that a usage on one voucher would
benefit_type=benefit_type, # mean all vouchers will have their usage decreased by one, hence each voucher needs
benefit_value=benefit_value, # it's own offer to keep track of it's own usages without interfering with others.
max_uses=max_uses, multi_offer = True if quantity > 1 and max_uses > 1 else False
coupon_id=coupon.id num_of_offers = quantity if multi_offer else 1
) for num in range(num_of_offers):
for __ in range(quantity): offer = _get_or_create_offer(
product_range=product_range,
benefit_type=benefit_type,
benefit_value=benefit_value,
max_uses=max_uses,
coupon_id=coupon.id,
offer_number=num
)
offers.append(offer)
for i in range(quantity):
voucher = _create_new_voucher( voucher = _create_new_voucher(
coupon=coupon, coupon=coupon,
end_datetime=end_datetime, end_datetime=end_datetime,
offer=offer, offer=offers[i] if multi_offer else offers[0],
start_datetime=start_datetime, start_datetime=start_datetime,
voucher_type=voucher_type, voucher_type=voucher_type,
code=code, code=code,
......
...@@ -100,15 +100,6 @@ define([ ...@@ -100,15 +100,6 @@ define([
expect(visible('[name=benefit_value]')).toBe(false); expect(visible('[name=benefit_value]')).toBe(false);
expect(visible('[name=code]')).toBe(false); expect(visible('[name=code]')).toBe(false);
}); });
it('should show the quantity field only for single-use vouchers', function () {
view.$el.find('[name=voucher_type]').val('Single use').trigger('change');
expect(visible('[name=quantity]')).toBe(true);
view.$el.find('[name=voucher_type]').val('Multi-use').trigger('change');
expect(visible('[name=quantity]')).toBe(false);
view.$el.find('[name=voucher_type]').val('Once per customer').trigger('change');
expect(visible('[name=quantity]')).toBe(false);
});
}); });
describe('discount code', function () { describe('discount code', function () {
......
...@@ -374,14 +374,6 @@ define([ ...@@ -374,14 +374,6 @@ define([
} else { } else {
this.hideField('[name=max_uses]', 1); this.hideField('[name=max_uses]', 1);
} }
// The only time we allow for a generation of multiple codes is
// when they are of type single use.
if (voucherType === 'Single use') {
this.formGroup('[name=quantity]').removeClass(this.hiddenClass);
} else {
this.hideField('[name=quantity]', 1);
}
}, },
/** /**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment