Commit 9e3a9029 by zubair-arbi Committed by Zubair Afzal

catalog coupons add course seat types selection

ENT-199
parent f9f6ab8a
...@@ -16,6 +16,7 @@ from oscar.apps.catalogue.categories import create_from_breadcrumbs ...@@ -16,6 +16,7 @@ from oscar.apps.catalogue.categories import create_from_breadcrumbs
from oscar.core.loading import get_class, get_model from oscar.core.loading import get_class, get_model
from oscar.test import factories from oscar.test import factories
from rest_framework import status from rest_framework import status
from testfixtures import LogCapture
from ecommerce.core.tests.decorators import mock_course_catalog_api_client from ecommerce.core.tests.decorators import mock_course_catalog_api_client
from ecommerce.coupons.tests.mixins import CourseCatalogMockMixin, CouponMixin from ecommerce.coupons.tests.mixins import CourseCatalogMockMixin, CouponMixin
...@@ -28,6 +29,7 @@ from ecommerce.tests.factories import ProductFactory, SiteConfigurationFactory ...@@ -28,6 +29,7 @@ from ecommerce.tests.factories import ProductFactory, SiteConfigurationFactory
from ecommerce.tests.mixins import ThrottlingMixin from ecommerce.tests.mixins import ThrottlingMixin
from ecommerce.tests.testcases import TestCase from ecommerce.tests.testcases import TestCase
Applicator = get_class('offer.utils', 'Applicator') Applicator = get_class('offer.utils', 'Applicator')
Basket = get_model('basket', 'Basket') Basket = get_model('basket', 'Basket')
Benefit = get_model('offer', 'Benefit') Benefit = get_model('offer', 'Benefit')
...@@ -636,16 +638,20 @@ class CouponViewSetFunctionalTest(CouponMixin, CourseCatalogTestMixin, CourseCat ...@@ -636,16 +638,20 @@ class CouponViewSetFunctionalTest(CouponMixin, CourseCatalogTestMixin, CourseCat
self.assertEqual(voucher_range.catalog_query, data['catalog_query']) self.assertEqual(voucher_range.catalog_query, data['catalog_query'])
self.assertEqual(voucher_range.course_seat_types, data['course_seat_types'][0]) self.assertEqual(voucher_range.course_seat_types, data['course_seat_types'][0])
def test_update_course_catalog(self): def test_update_course_catalog_coupon(self):
""" """
Test updating course catalog range value deletes catalog, Test that on updating a coupon as course catalog coupon with course
catalog_query and course_seat_types from that voucher range. seats, deletes values for fields "catalog" and "catalog_query" from its
related voucher range.
""" """
path = reverse('api:v2:coupons-detail', kwargs={'pk': self.coupon.id}) path = reverse('api:v2:coupons-detail', kwargs={'pk': self.coupon.id})
course_catalog_id = {'id': 1, 'name': 'Test catalog'} course_catalog = {'id': 1, 'name': 'Test catalog'}
course_seat_types = ['verified']
data = { data = {
'id': self.coupon.id, 'id': self.coupon.id,
'course_catalog': course_catalog_id 'course_catalog': course_catalog,
'course_seat_types': course_seat_types,
} }
self.client.put(path, json.dumps(data), 'application/json') self.client.put(path, json.dumps(data), 'application/json')
...@@ -653,10 +659,40 @@ class CouponViewSetFunctionalTest(CouponMixin, CourseCatalogTestMixin, CourseCat ...@@ -653,10 +659,40 @@ class CouponViewSetFunctionalTest(CouponMixin, CourseCatalogTestMixin, CourseCat
vouchers = updated_coupon.attr.coupon_vouchers.vouchers vouchers = updated_coupon.attr.coupon_vouchers.vouchers
voucher_range = vouchers.first().offers.first().benefit.range voucher_range = vouchers.first().offers.first().benefit.range
expected_course_seat_types = ','.join(course_seat_types)
self.assertEqual(voucher_range.catalog, None) self.assertEqual(voucher_range.catalog, None)
self.assertEqual(voucher_range.catalog_query, None) self.assertEqual(voucher_range.catalog_query, None)
self.assertEqual(voucher_range.course_seat_types, None) self.assertEqual(voucher_range.course_seat_types, expected_course_seat_types)
self.assertEqual(voucher_range.course_catalog, course_catalog_id['id']) self.assertEqual(voucher_range.course_catalog, course_catalog['id'])
def test_update_course_catalog_coupon_without_seat_types(self):
"""
Test that on updating a coupon as a course catalog coupon without any
course seat types, a validation error message is logged along with a
400 http response.
"""
path = reverse('api:v2:coupons-detail', kwargs={'pk': self.coupon.id})
data = {
'id': self.coupon.id,
'course_catalog': {'id': 1, 'name': 'Test catalog'},
'course_seat_types': [],
}
logger_name = 'ecommerce.core.utils'
expected_logger_message = 'Failed to create Range. Either catalog_query or course_catalog must be given ' \
'but not both and course_seat_types fields must be set.'
with LogCapture(logger_name) as logger:
response = self.client.put(path, json.dumps(data), 'application/json')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
logger.check(
(
logger_name,
'ERROR',
expected_logger_message
)
)
def test_update_coupon_benefit_value(self): def test_update_coupon_benefit_value(self):
vouchers = self.coupon.attr.coupon_vouchers.vouchers.all() vouchers = self.coupon.attr.coupon_vouchers.vouchers.all()
......
...@@ -286,10 +286,9 @@ class CouponViewSet(EdxOrderPlacementMixin, viewsets.ModelViewSet): ...@@ -286,10 +286,9 @@ class CouponViewSet(EdxOrderPlacementMixin, viewsets.ModelViewSet):
course_catalog = course_catalog_data.get('id') course_catalog = course_catalog_data.get('id')
range_data['course_catalog'] = course_catalog range_data['course_catalog'] = course_catalog
# Remove catalog_query and course_seat_types, switching from # Remove catalog_query, switching from the dynamic query coupon to
# dynamic query to course catalog # course catalog coupon
range_data['catalog_query'] = None range_data['catalog_query'] = None
range_data['course_seat_types'] = None
else: else:
range_data['course_catalog'] = None range_data['course_catalog'] = None
...@@ -299,7 +298,10 @@ class CouponViewSet(EdxOrderPlacementMixin, viewsets.ModelViewSet): ...@@ -299,7 +298,10 @@ class CouponViewSet(EdxOrderPlacementMixin, viewsets.ModelViewSet):
else: else:
range_data['enterprise_customer'] = None range_data['enterprise_customer'] = None
Range.objects.filter(id=voucher_range.id).update(**range_data) for attr, value in range_data.iteritems():
setattr(voucher_range, attr, value)
voucher_range.save()
def update(self, request, *args, **kwargs): def update(self, request, *args, **kwargs):
"""Update coupon depending on request data sent.""" """Update coupon depending on request data sent."""
......
...@@ -89,7 +89,9 @@ define([ ...@@ -89,7 +89,9 @@ define([
} }
}, },
course_seat_types: function (val) { course_seat_types: function (val) {
if (this.get('catalog_type') === CATALOG_TYPES.multiple_courses && val.length === 0) { // add validation only for dynamic coupons, e.g. dynamic query coupon or catalog coupon
var dynamicCoupons = [CATALOG_TYPES.multiple_courses, CATALOG_TYPES.catalog];
if (dynamicCoupons.indexOf(this.get('catalog_type')) !== -1 && val.length === 0) {
return Backbone.Validation.messages.seat_types; return Backbone.Validation.messages.seat_types;
} }
}, },
......
...@@ -92,7 +92,7 @@ define([ ...@@ -92,7 +92,7 @@ define([
expect(model.isValid()).toBeTruthy(); expect(model.isValid()).toBeTruthy();
}); });
it('should validate course catalog for type Catalog', function () { it('should validate course catalog and course seat types for type Catalog', function () {
model.set('catalog_type', 'Catalog'); model.set('catalog_type', 'Catalog');
model.set('course_catalog', ''); model.set('course_catalog', '');
model.validate(); model.validate();
...@@ -103,6 +103,12 @@ define([ ...@@ -103,6 +103,12 @@ define([
expect(model.isValid()).toBe(false); expect(model.isValid()).toBe(false);
model.set('course_catalog', '1'); model.set('course_catalog', '1');
model.set('course_seat_types', []);
model.validate();
expect(model.isValid()).toBe(false);
model.set('course_catalog', '1');
model.set('course_seat_types', ['verified']);
model.validate(); model.validate();
expect(model.isValid()).toBe(true); expect(model.isValid()).toBe(true);
}); });
......
...@@ -140,14 +140,20 @@ define([ ...@@ -140,14 +140,20 @@ define([
expect(view.$('.invoice-discount-type > .value').text()).toEqual(''); expect(view.$('.invoice-discount-type > .value').text()).toEqual('');
}); });
it('should display course catalog name on render.', function() { it('should display course catalog name and course seats without preview button on render.', function() {
ecommerce.coupons.catalogs = new CatalogCollection([{id: 1, name: 'Test Catalog'}]); ecommerce.coupons.catalogs = new CatalogCollection([{id: 1, name: 'Test Catalog'}]);
data.course_catalog = 1; data.course_catalog = 1;
data.course_seat_types = ['verified'];
model = Coupon.findOrCreate(data, {parse: true, create: true}); model = Coupon.findOrCreate(data, {parse: true, create: true});
view = new CouponDetailView({model: model}); view = new CouponDetailView({model: model});
view.render(); view.render();
expect(view.$('.catalog-name > .value').text()).toEqual('Test Catalog'); expect(view.$('.catalog-name > .value').text()).toEqual('Test Catalog');
expect(view.$('.seat-types .value').text()).toEqual(
data.course_seat_types.join(', ')
);
expect(view.$('.catalog_buttons').text()).toEqual('');
}); });
it('should format seat types.', function() { it('should format seat types.', function() {
......
...@@ -153,14 +153,16 @@ define([ ...@@ -153,14 +153,16 @@ define([
this.renderCourseData(); this.renderCourseData();
this.delegateEvents(); this.delegateEvents();
this.dynamic_catalog_view = new DynamicCatalogView({ if (this.model.get('catalog_type') === this.model.catalogTypes.multiple_courses) {
'query': this.model.get('catalog_query'), this.dynamic_catalog_view = new DynamicCatalogView({
'seat_types': this.model.get('course_seat_types') 'query': this.model.get('catalog_query'),
}); 'seat_types': this.model.get('course_seat_types')
});
this.dynamic_catalog_view.$el = this.$('.catalog_buttons');
this.dynamic_catalog_view.render(); this.dynamic_catalog_view.$el = this.$('.catalog_buttons');
this.dynamic_catalog_view.delegateEvents(); this.dynamic_catalog_view.render();
this.dynamic_catalog_view.delegateEvents();
}
this.$('.coupon-information').before(AlertDivTemplate); this.$('.coupon-information').before(AlertDivTemplate);
this.$alerts = this.$el.find('.alerts'); this.$alerts = this.$el.find('.alerts');
......
...@@ -480,15 +480,19 @@ define([ ...@@ -480,15 +480,19 @@ define([
this.model.unset('seat_type'); this.model.unset('seat_type');
this.model.unset('stock_record_ids'); this.model.unset('stock_record_ids');
this.model.unset('catalog_query'); this.model.unset('catalog_query');
this.model.unset('course_seat_types');
this.formGroup('[name=enterprise_customer]').addClass(this.hiddenClass); this.formGroup('[name=enterprise_customer]').addClass(this.hiddenClass);
this.model.unset('enterprise_customer'); this.model.unset('enterprise_customer');
this.formGroup('[name=catalog_query]').addClass(this.hiddenClass); this.formGroup('[name=catalog_query]').addClass(this.hiddenClass);
this.formGroup('[name=course_seat_types]').addClass(this.hiddenClass); this.formGroup('[name=course_seat_types]').removeClass(this.hiddenClass);
this.formGroup('[name=course_id]').addClass(this.hiddenClass); this.formGroup('[name=course_id]').addClass(this.hiddenClass);
this.formGroup('[name=seat_type]').addClass(this.hiddenClass); this.formGroup('[name=seat_type]').addClass(this.hiddenClass);
this.formGroup('[name=course_catalog]').removeClass(this.hiddenClass); this.formGroup('[name=course_catalog]').removeClass(this.hiddenClass);
this.formGroup('[name=seat_type] option').remove(); this.formGroup('[name=seat_type] option').remove();
this.$('.catalog_buttons').addClass(this.hiddenClass);
if (!this.model.get('course_seat_types')) {
this.model.set('course_seat_types', []);
}
} else { } else {
this.formGroup('[name=catalog_query]').removeClass(this.hiddenClass); this.formGroup('[name=catalog_query]').removeClass(this.hiddenClass);
this.formGroup('[name=course_seat_types]').removeClass(this.hiddenClass); this.formGroup('[name=course_seat_types]').removeClass(this.hiddenClass);
...@@ -502,6 +506,7 @@ define([ ...@@ -502,6 +506,7 @@ define([
this.model.unset('stock_record_ids'); this.model.unset('stock_record_ids');
this.model.set('course_catalog', this.model.defaults.course_catalog); this.model.set('course_catalog', this.model.defaults.course_catalog);
this.$('.catalog_buttons').removeClass(this.hiddenClass);
if (!this.model.get('course_seat_types')) { if (!this.model.get('course_seat_types')) {
this.model.set('course_seat_types', []); this.model.set('course_seat_types', []);
} }
......
...@@ -185,6 +185,11 @@ ...@@ -185,6 +185,11 @@
<span>Query length: <span class="query_length">0</span></span> <span>Query length: <span class="query_length">0</span></span>
<p class="help-block"></p> <p class="help-block"></p>
</div> </div>
<div class="form-group course-catalog">
<label for="course-catalog"><%= gettext('Select from course catalogs:') %> *</label>
<select id="course-catalog" class="form-control" name="course_catalog"></select>
<p class="help-block"></p>
</div>
<div class="form-group course-seat-types"> <div class="form-group course-seat-types">
<label for="course-seat-types"><%= gettext('Seat Types:') %> *</label> <label for="course-seat-types"><%= gettext('Seat Types:') %> *</label>
<div class="checkboxes"> <div class="checkboxes">
...@@ -206,11 +211,6 @@ ...@@ -206,11 +211,6 @@
</div> </div>
<div class="catalog_buttons"></div> <div class="catalog_buttons"></div>
</div> </div>
<div class="form-group course-catalog">
<label for="course-catalog"><%= gettext('Select from course catalogs:') %> *</label>
<select id="course-catalog" class="form-control" name="course_catalog"></select>
<p class="help-block"></p>
</div>
<div class="form-group enterprise-customer"> <div class="form-group enterprise-customer">
<label for="enterprise-customer"><%= gettext('Enterprise Customer:') %></label> <label for="enterprise-customer"><%= gettext('Enterprise Customer:') %></label>
<select id="enterprise-customer" class="form-control" name="enterprise_customer"></select> <select id="enterprise-customer" class="form-control" name="enterprise_customer"></select>
......
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