Commit 831dadc6 by Michael Terry Committed by Michael Terry

Be entitlement-aware for new courses

When creating a new course in publisher, require type and price
up front rather than waiting until creating a course run. (only for
verified and professional courses)

And hide this feature behind a waffle flag.

LEARNER-3767
parent 5a3c096b
......@@ -14,3 +14,6 @@ PARTNER_SUPPORT_GROUP_NAME = 'Partner Support Members'
# Being used in old migration `0019_create_user_groups`.
PARTNER_COORDINATOR_GROUP_NAME = 'Partner Coordinators'
# Waffle flags
PUBLISHER_ENTITLEMENTS_WAFFLE_SWITCH = 'publisher_entitlements'
......@@ -17,8 +17,8 @@ from course_discovery.apps.ietf_language_tags.models import LanguageTag
from course_discovery.apps.publisher.choices import CourseRunStateChoices, PublisherUserRole
from course_discovery.apps.publisher.mixins import LanguageModelSelect2Multiple, get_user_organizations
from course_discovery.apps.publisher.models import (
Course, CourseRun, CourseRunState, CourseState, CourseUserRole, OrganizationExtension, OrganizationUserRole,
PublisherUser, Seat, User
Course, CourseEntitlement, CourseRun, CourseRunState, CourseState, CourseUserRole, OrganizationExtension,
OrganizationUserRole, PublisherUser, Seat, User
)
from course_discovery.apps.publisher.utils import VALID_CHARS_IN_COURSE_NUM_AND_ORG_KEY, is_internal_user
from course_discovery.apps.publisher.validators import validate_text_count
......@@ -442,6 +442,45 @@ class SeatForm(BaseForm):
seat.credit_price = 0.00
class CourseEntitlementForm(BaseForm):
MODE_CHOICES = [
('', _('Audit only or credit')),
(CourseEntitlement.VERIFIED, _('Verified')),
(CourseEntitlement.PROFESSIONAL, _('Professional education')),
]
mode = forms.ChoiceField(choices=MODE_CHOICES, required=False, label=_('Enrollment Track'),
initial=CourseEntitlement.VERIFIED)
price = forms.DecimalField(max_digits=6, decimal_places=2, required=False, initial=0.00)
class Meta:
fields = ('mode', 'price')
model = CourseEntitlement
def save(self, commit=True, course=None): # pylint: disable=arguments-differ
entitlement = super(CourseEntitlementForm, self).save(commit=False)
if course:
entitlement.course = course
if commit:
entitlement.save()
return entitlement
def clean(self):
cleaned_data = super().clean()
mode = cleaned_data.get('mode')
price = cleaned_data.get('price')
has_mode = bool(mode)
has_price = price is not None and price > 0
if has_mode != has_price:
raise ValidationError({'price': ''}) # mimics required field behavior (red border only, no error string)
return cleaned_data
class BaseUserAdminForm(forms.ModelForm):
"""This form will be use for type ahead search in django-admin."""
......
......@@ -128,6 +128,27 @@
{% endif %}
</div>
</div>
{% if entitlement_form %}
<div class="field-title">{% trans "CERTIFICATE TYPE AND PRICE" %}</span></div>
<div class="row">
<div class="col col-6 help-text">
{% trans "If the course offers a verified or professional education certificate, select the certificate type and enter the price for the certificate." %}
</div>
<div class="col col-6">
<div class="row">
<div class="col col-6">
<label class="field-label ">{{ entitlement_form.mode.label_tag }}</label>
{{ entitlement_form.mode }}
</div>
<div id="seatPriceBlock" class="col col-6 {% if not entitlement_form.mode.value %}hidden{% endif %}">
<label class="field-label ">{{ entitlement_form.price.label_tag }} <span class="required">*</span></label>
{{ entitlement_form.price }}
</div>
</div>
</div>
</div>
{% endif %}
</fieldset>
</div>
</div>
......
......@@ -126,7 +126,7 @@
<label class="field-label ">{{ seat_form.type.label_tag }}
</label> {{ seat_form.type }}
</div>
<div id="SeatPriceBlock" class="col col-6 {% if seat_form.type.value == 'audit' or not seat_form.price.value %}hidden{% endif %}">
<div id="seatPriceBlock" class="col col-6 {% if seat_form.type.value == 'audit' or not seat_form.price.value %}hidden{% endif %}">
<label class="field-label ">{{ seat_form.price.label_tag }}</label>
{{ seat_form.price }}
<div class="{% if seat_form.type.value != 'credit' or not seat_form.credit_price.value %}hidden{% endif %}" id="creditPrice">
......
......@@ -184,7 +184,7 @@
<label class="field-label ">{{ seat_form.type.label_tag }}
</label> {{ seat_form.type }}
</div>
<div id="SeatPriceBlock" class="col col-6 {% if seat_form.type.value == 'audit' or not seat_form.price.value %}hidden{% endif %}">
<div id="seatPriceBlock" class="col col-6 {% if seat_form.type.value == 'audit' or not seat_form.price.value %}hidden{% endif %}">
<label class="field-label ">{{ seat_form.price.label_tag }}</label>
{{ seat_form.price }}
<div class="{% if seat_form.type.value != 'credit' or not seat_form.credit_price.value %}hidden{% endif %}" id="creditPrice">
......
......@@ -12,9 +12,10 @@ from course_discovery.apps.core.tests.factories import UserFactory
from course_discovery.apps.course_metadata.tests.factories import OrganizationFactory
from course_discovery.apps.publisher.choices import CourseRunStateChoices, PublisherUserRole
from course_discovery.apps.publisher.forms import (
CourseForm, CourseRunForm, CourseRunStateAdminForm, CourseStateAdminForm, PublisherUserCreationForm, SeatForm
CourseEntitlementForm, CourseForm, CourseRunForm, CourseRunStateAdminForm, CourseStateAdminForm,
PublisherUserCreationForm, SeatForm
)
from course_discovery.apps.publisher.models import Seat
from course_discovery.apps.publisher.models import CourseEntitlement, Seat
from course_discovery.apps.publisher.tests.factories import (
CourseFactory, CourseUserRoleFactory, OrganizationExtensionFactory, SeatFactory
)
......@@ -344,6 +345,51 @@ class PublisherCustomCourseFormTests(TestCase):
assert course.title == 'áçã'
@ddt.ddt
class PublisherCourseEntitlementFormTests(TestCase):
@ddt.data(
(None, 50),
(CourseEntitlement.VERIFIED, None),
(CourseEntitlement.PROFESSIONAL, None),
(CourseEntitlement.PROFESSIONAL, 0),
(CourseEntitlement.PROFESSIONAL, -1),
)
@ddt.unpack
def test_invalid_price(self, mode, price):
"""
Verify that clean raises an error if the price is invalid for the course type
"""
entitlement_form = CourseEntitlementForm()
entitlement_form.cleaned_data = {}
if mode is not None:
entitlement_form.cleaned_data['mode'] = mode
if price is not None:
entitlement_form.cleaned_data['price'] = price
with self.assertRaises(ValidationError):
entitlement_form.clean()
@ddt.data(
(None, None),
(None, 0),
(CourseEntitlement.VERIFIED, 50),
(CourseEntitlement.PROFESSIONAL, 50),
)
@ddt.unpack
def test_valid_price(self, mode, price):
"""
Verify that clean works fine for valid price/type combos
"""
entitlement_form = CourseEntitlementForm()
entitlement_form.cleaned_data = {}
if mode is not None:
entitlement_form.cleaned_data['mode'] = mode
if price is not None:
entitlement_form.cleaned_data['price'] = price
self.assertEqual(entitlement_form.clean(), entitlement_form.cleaned_data)
@pytest.mark.django_db
class TestSeatForm:
@override_switch('publisher_create_audit_seats_for_verified_course_runs', active=True)
......
......@@ -34,10 +34,11 @@ from course_discovery.apps.publisher.choices import (
CourseRunStateChoices, CourseStateChoices, InternalUserRole, PublisherUserRole
)
from course_discovery.apps.publisher.constants import (
ADMIN_GROUP_NAME, INTERNAL_USER_GROUP_NAME, PROJECT_COORDINATOR_GROUP_NAME, REVIEWER_GROUP_NAME
ADMIN_GROUP_NAME, INTERNAL_USER_GROUP_NAME, PROJECT_COORDINATOR_GROUP_NAME, PUBLISHER_ENTITLEMENTS_WAFFLE_SWITCH,
REVIEWER_GROUP_NAME
)
from course_discovery.apps.publisher.models import (
Course, CourseRun, CourseRunState, CourseState, OrganizationExtension, Seat
Course, CourseEntitlement, CourseRun, CourseRunState, CourseState, OrganizationExtension, Seat
)
from course_discovery.apps.publisher.tests import factories
from course_discovery.apps.publisher.tests.utils import create_non_staff_user_and_login
......@@ -282,6 +283,71 @@ class CreateCourseViewTests(SiteMixin, TestCase):
target_status_code=200
)
def _create_course_with_post(self, data=None):
initial_data = {'title': 'Test Course', 'number': 'test1', 'image': ''}
if data:
initial_data.update(**data)
course_dict = self._post_data(initial_data, self.course)
response = self.client.post(reverse('publisher:publisher_courses_new'), course_dict)
self.assertRedirects(
response,
expected_url=reverse('publisher:publisher_course_detail', kwargs={'pk': Course.objects.first().id}),
status_code=302,
target_status_code=200
)
return Course.objects.get(number=course_dict['number'])
@ddt.data(CourseEntitlement.VERIFIED, CourseEntitlement.PROFESSIONAL)
def test_create_entitlement(self, mode):
"""
Verify that we create an entitlement for appropriate types (happy path)
"""
toggle_switch(PUBLISHER_ENTITLEMENTS_WAFFLE_SWITCH, True)
data = {'mode': mode, 'price': 50}
course = self._create_course_with_post(data)
self.assertEqual(1, CourseEntitlement.objects.all().count())
self.assertEqual(1, course.entitlements.all().count())
self.assertEqual(Course.ENTITLEMENT_VERSION, course.version)
entitlement = course.entitlements.first()
self.assertEqual(course, entitlement.course)
self.assertEqual(mode, entitlement.mode)
self.assertEqual(50, entitlement.price)
def test_no_entitlement_created_without_switch(self):
"""
Verify that when we create a verified seat without the entitlement waffle switch enabled, we set version right
"""
toggle_switch(PUBLISHER_ENTITLEMENTS_WAFFLE_SWITCH, False)
data = {'mode': CourseEntitlement.VERIFIED, 'price': 50}
course = self._create_course_with_post(data)
self.assertEqual(0, CourseEntitlement.objects.all().count())
self.assertEqual(Course.SEAT_VERSION, course.version)
def test_seat_version(self):
"""
Verify that when we create a seat product without an entitlement, we set version correctly
"""
toggle_switch(PUBLISHER_ENTITLEMENTS_WAFFLE_SWITCH, True)
course = self._create_course_with_post()
self.assertEqual(0, CourseEntitlement.objects.all().count())
self.assertEqual(Course.SEAT_VERSION, course.version)
@ddt.data(0, -1, None)
def test_invalid_entitlement_price(self, price):
"""
Verify that we check price validity when making an entitlement
"""
toggle_switch(PUBLISHER_ENTITLEMENTS_WAFFLE_SWITCH, True)
data = {'title': 'Test2', 'number': 'testX234', 'mode': CourseEntitlement.VERIFIED}
if price is not None:
data['price'] = price
course_dict = self._post_data(data, self.course)
response = self.client.post(reverse('publisher:publisher_courses_new'), course_dict)
self.assertEqual(response.status_code, 400)
class CreateCourseRunViewTests(SiteMixin, TestCase):
""" Tests for the publisher `CreateCourseRunView`. """
......@@ -2867,7 +2933,7 @@ class CourseRunEditViewTests(SiteMixin, TestCase):
self.edit_page_url = reverse('publisher:publisher_course_runs_edit', kwargs={'pk': self.course_run.id})
response = self.client.get(self.edit_page_url)
self.assertEqual(response.status_code, 200)
self.assertNotContains(response, '<div id="SeatPriceBlock" class="col col-6 hidden" style="display: block;">')
self.assertNotContains(response, '<div id="seatPriceBlock" class="col col-6 hidden" style="display: block;">')
def test_get_context_data_with_pc(self):
"""
......@@ -3204,7 +3270,7 @@ class CourseRunEditViewTests(SiteMixin, TestCase):
"""
self.user.groups.add(Group.objects.get(name=INTERNAL_USER_GROUP_NAME))
response = self.client.get(self.edit_page_url)
self.assertNotContains(response, '<div id="SeatPriceBlock" class="col col-6 hidden" style="display: block;">')
self.assertNotContains(response, '<div id="seatPriceBlock" class="col col-6 hidden" style="display: block;">')
@ddt.data(Seat.PROFESSIONAL, Seat.VERIFIED)
def test_price_visible(self, seat_type):
......@@ -3220,7 +3286,7 @@ class CourseRunEditViewTests(SiteMixin, TestCase):
self.client.post(self.edit_page_url, updated_dict)
response = self.client.get(self.edit_page_url)
self.assertContains(response, '<div id="SeatPriceBlock" class="col col-6')
self.assertContains(response, '<div id="seatPriceBlock" class="col col-6')
def test_page_with_enable_waffle_switch(self):
"""
......
......@@ -27,10 +27,11 @@ from course_discovery.apps.course_metadata.models import Person
from course_discovery.apps.ietf_language_tags.models import LanguageTag
from course_discovery.apps.publisher import emails, mixins, serializers
from course_discovery.apps.publisher.choices import CourseRunStateChoices, CourseStateChoices, PublisherUserRole
from course_discovery.apps.publisher.constants import PUBLISHER_ENTITLEMENTS_WAFFLE_SWITCH
from course_discovery.apps.publisher.dataloader.create_courses import process_course
from course_discovery.apps.publisher.emails import send_email_for_published_course_run_editing
from course_discovery.apps.publisher.forms import (AdminImportCourseForm, CourseForm, CourseRunForm, CourseSearchForm,
SeatForm)
from course_discovery.apps.publisher.forms import (AdminImportCourseForm, CourseEntitlementForm, CourseForm,
CourseRunForm, CourseSearchForm, SeatForm)
from course_discovery.apps.publisher.models import (PAID_SEATS, Course, CourseRun, CourseRunState, CourseState,
CourseUserRole, OrganizationExtension, Seat, UserAttributes)
from course_discovery.apps.publisher.utils import (get_internal_users, has_role_for_course, is_internal_user,
......@@ -237,6 +238,7 @@ class CreateCourseView(mixins.LoginRequiredMixin, mixins.PublisherUserRequiredMi
""" Create Course View."""
model = Course
course_form = CourseForm
entitlement_form = CourseEntitlementForm
template_name = 'publisher/add_course_form.html'
success_url = 'publisher:publisher_course_detail'
......@@ -247,11 +249,14 @@ class CreateCourseView(mixins.LoginRequiredMixin, mixins.PublisherUserRequiredMi
return success_url
def get_context_data(self):
return {
data = {
'course_form': self.course_form(user=self.request.user),
'publisher_hide_features_for_pilot': waffle.switch_is_active('publisher_hide_features_for_pilot'),
'publisher_add_instructor_feature': waffle.switch_is_active('publisher_add_instructor_feature'),
}
if waffle.switch_is_active(PUBLISHER_ENTITLEMENTS_WAFFLE_SWITCH):
data['entitlement_form'] = self.entitlement_form()
return data
def get(self, request, *args, **kwargs):
return render(request, self.template_name, self.get_context_data())
......@@ -260,6 +265,8 @@ class CreateCourseView(mixins.LoginRequiredMixin, mixins.PublisherUserRequiredMi
ctx = self.get_context_data()
add_new_run = request.POST.get('add_new_run')
support_entitlements = waffle.switch_is_active(PUBLISHER_ENTITLEMENTS_WAFFLE_SWITCH)
# pass selected organization to CourseForm to populate related
# choices into institution admin field
user = self.request.user
......@@ -268,15 +275,24 @@ class CreateCourseView(mixins.LoginRequiredMixin, mixins.PublisherUserRequiredMi
course_form = self.course_form(
request.POST, request.FILES, user=user, organization=organization
)
if course_form.is_valid():
entitlement_form = self.entitlement_form(request.POST)
if course_form.is_valid() and entitlement_form.is_valid():
try:
with transaction.atomic():
course = course_form.save(commit=False)
if entitlement_form['mode'].value() and support_entitlements:
course.version = Course.ENTITLEMENT_VERSION
else:
course.version = Course.SEAT_VERSION
course.changed_by = user
course.save()
# commit false does not save m2m object. Keyword field is m2m.
course_form.save_m2m()
# Now create entitlement if we need to
if course.version == Course.ENTITLEMENT_VERSION:
entitlement_form.save(course=course)
organization_extension = get_object_or_404(
OrganizationExtension, organization=course_form.data['organization']
)
......@@ -329,6 +345,9 @@ class CreateCourseView(mixins.LoginRequiredMixin, mixins.PublisherUserRequiredMi
'course_form': course_form,
}
)
if support_entitlements:
ctx['entitlement_form'] = entitlement_form
return render(request, self.template_name, ctx, status=400)
......
......@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-02-02 18:41+0000\n"
"POT-Creation-Date: 2018-02-05 18:37+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......@@ -832,6 +832,10 @@ msgid "Only audit seat can be without price."
msgstr ""
#: apps/publisher/forms.py
msgid "Audit only or credit"
msgstr ""
#: apps/publisher/forms.py
msgid "This field is required."
msgstr ""
......@@ -1389,6 +1393,20 @@ msgid "BIO1.1x; BIO1.2x etc."
msgstr ""
#: apps/publisher/templates/publisher/add_course_form.html
#: apps/publisher/templates/publisher/add_courserun_form.html
#: apps/publisher/templates/publisher/course_run/edit_run_form.html
msgid "CERTIFICATE TYPE AND PRICE"
msgstr ""
#: apps/publisher/templates/publisher/add_course_form.html
#: apps/publisher/templates/publisher/add_courserun_form.html
#: apps/publisher/templates/publisher/course_run/edit_run_form.html
msgid ""
"If the course offers a verified or professional education certificate, "
"select the certificate type and enter the price for the certificate."
msgstr ""
#: apps/publisher/templates/publisher/add_course_form.html
msgid "I want to add a run to this course at this time"
msgstr ""
......@@ -1475,18 +1493,6 @@ msgid ""
msgstr ""
#: apps/publisher/templates/publisher/add_courserun_form.html
#: apps/publisher/templates/publisher/course_run/edit_run_form.html
msgid "CERTIFICATE TYPE AND PRICE"
msgstr ""
#: apps/publisher/templates/publisher/add_courserun_form.html
#: apps/publisher/templates/publisher/course_run/edit_run_form.html
msgid ""
"If the course offers a verified or professional education certificate, "
"select the certificate type and enter the price for the certificate."
msgstr ""
#: apps/publisher/templates/publisher/add_courserun_form.html
msgid "Create New Course Run"
msgstr ""
......
......@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-02-02 18:41+0000\n"
"POT-Creation-Date: 2018-02-05 18:37+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......
......@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-02-02 18:41+0000\n"
"POT-Creation-Date: 2018-02-05 18:37+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......@@ -1001,6 +1001,10 @@ msgstr ""
"¢σηѕє¢тєтυ#"
#: apps/publisher/forms.py
msgid "Audit only or credit"
msgstr "Àüdït önlý ör çrédït Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #"
#: apps/publisher/forms.py
msgid "This field is required."
msgstr "Thïs fïéld ïs réqüïréd. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σ#"
......@@ -1612,6 +1616,28 @@ msgid "BIO1.1x; BIO1.2x etc."
msgstr "BÌÖ1.1x; BÌÖ1.2x étç. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #"
#: apps/publisher/templates/publisher/add_course_form.html
#: apps/publisher/templates/publisher/add_courserun_form.html
#: apps/publisher/templates/publisher/course_run/edit_run_form.html
msgid "CERTIFICATE TYPE AND PRICE"
msgstr "ÇÉRTÌFÌÇÀTÉ TÝPÉ ÀND PRÌÇÉ Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#"
#: apps/publisher/templates/publisher/add_course_form.html
#: apps/publisher/templates/publisher/add_courserun_form.html
#: apps/publisher/templates/publisher/course_run/edit_run_form.html
msgid ""
"If the course offers a verified or professional education certificate, "
"select the certificate type and enter the price for the certificate."
msgstr ""
"Ìf thé çöürsé öfférs ä vérïfïéd ör pröféssïönäl édüçätïön çértïfïçäté, "
"séléçt thé çértïfïçäté týpé änd éntér thé prïçé för thé çértïfïçäté. Ⱡ'σяєм "
"ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ єιυѕмσ∂ тємρσя "
"ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα αłιqυα. υт єηιм α∂ мιηιм νєηιαм, qυιѕ "
"ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα ¢σммσ∂σ "
"¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє "
"¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт ¢υρι∂αтαт "
"ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕєяυηт мσłłιт αηιм ι∂ єѕт łα#"
#: apps/publisher/templates/publisher/add_course_form.html
msgid "I want to add a run to this course at this time"
msgstr ""
"Ì wänt tö ädd ä rün tö thïs çöürsé ät thïs tïmé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт,"
......@@ -1736,26 +1762,6 @@ msgstr ""
"ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢α#"
#: apps/publisher/templates/publisher/add_courserun_form.html
#: apps/publisher/templates/publisher/course_run/edit_run_form.html
msgid "CERTIFICATE TYPE AND PRICE"
msgstr "ÇÉRTÌFÌÇÀTÉ TÝPÉ ÀND PRÌÇÉ Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#"
#: apps/publisher/templates/publisher/add_courserun_form.html
#: apps/publisher/templates/publisher/course_run/edit_run_form.html
msgid ""
"If the course offers a verified or professional education certificate, "
"select the certificate type and enter the price for the certificate."
msgstr ""
"Ìf thé çöürsé öfférs ä vérïfïéd ör pröféssïönäl édüçätïön çértïfïçäté, "
"séléçt thé çértïfïçäté týpé änd éntér thé prïçé för thé çértïfïçäté. Ⱡ'σяєм "
"ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ єιυѕмσ∂ тємρσя "
"ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα αłιqυα. υт єηιм α∂ мιηιм νєηιαм, qυιѕ "
"ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα ¢σммσ∂σ "
"¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт єѕѕє "
"¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт ¢υρι∂αтαт "
"ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕєяυηт мσłłιт αηιм ι∂ єѕт łα#"
#: apps/publisher/templates/publisher/add_courserun_form.html
msgid "Create New Course Run"
msgstr "Çréäté Néw Çöürsé Rün Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #"
......
......@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-02-02 18:41+0000\n"
"POT-Creation-Date: 2018-02-05 18:37+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......
$(document).on('change', '#id_type', function (e) {
var $seatBlock = $("#SeatPriceBlock"),
$(document).on('change', '#id_type, #id_mode', function (e) {
var $seatBlock = $("#seatPriceBlock"),
$creditPrice = $("#creditPrice"),
selectedSeatType = this.value;
if (selectedSeatType === 'audit' || selectedSeatType === '') {
......
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