Commit 9aa095dd by Diana Huang Committed by Julia Hansbrough

Adapt flow for new 'professional' mode.

ECOM-41
parent 805c3256
......@@ -113,6 +113,21 @@ class CourseMode(models.Model):
return None
@classmethod
def verified_mode_for_course(cls, course_id):
"""
Since we have two separate modes that can go through the verify flow,
we want to be able to select the 'correct' verified mode for a given course.
Currently, we prefer to return the professional mode over the verified one
if both exist for the given course.
"""
modes_dict = cls.modes_for_course_dict(course_id)
verified_mode = modes_dict.get('verified', None)
professional_mode = modes_dict.get('professional', None)
# we prefer professional over verify
return professional_mode if professional_mode else verified_mode
@classmethod
def min_course_price_for_verified_for_currency(cls, course_id, currency):
"""
Returns the minimum price of the course int he appropriate currency over all the
......
......@@ -113,3 +113,17 @@ class CourseModeModelTest(TestCase):
modes = CourseMode.modes_for_course(SlashSeparatedCourseKey('TestOrg', 'TestCourse', 'TestRun'))
self.assertEqual([CourseMode.DEFAULT_MODE], modes)
def test_verified_mode_for_course(self):
self.create_mode('verified', 'Verified Certificate')
mode = CourseMode.verified_mode_for_course(self.course_key)
self.assertEqual(mode.slug, 'verified')
# verify that the professional mode is preferred
self.create_mode('professional', 'Professional Education Verified Certificate')
mode = CourseMode.verified_mode_for_course(self.course_key)
self.assertEqual(mode.slug, 'professional')
......@@ -59,8 +59,6 @@ class ChooseModeView(View):
)
)
donation_for_course = request.session.get("donation_for_course", {})
chosen_price = donation_for_course.get(course_key, None)
......@@ -135,11 +133,6 @@ class ChooseModeView(View):
donation_for_course = request.session.get("donation_for_course", {})
donation_for_course[course_key] = amount_value
request.session["donation_for_course"] = donation_for_course
if SoftwareSecurePhotoVerification.user_has_valid_or_pending(request.user):
return redirect(
reverse('verify_student_verified',
kwargs={'course_id': course_key.to_deprecated_string()}) + "?upgrade={}".format(upgrade)
)
return redirect(
reverse('verify_student_show_requirements',
......
......@@ -701,8 +701,13 @@ class CertificateItem(OrderItem):
item.qty = 1
item.unit_cost = cost
course_name = modulestore().get_course(course_id).display_name
item.line_desc = _("Certificate of Achievement, {mode_name} for course {course}").format(mode_name=mode_info.name,
course=course_name)
# Translators: In this particular case, mode_name refers to a
# particular mode (i.e. Honor Code Certificate, Verified Certificate, etc)
# by which a user could enroll in the given course.
item.line_desc = _("{mode_name} for course {course}").format(
mode_name=mode_info.name,
course=course_name
)
item.currency = currency
order.currency = currency
order.save()
......@@ -725,7 +730,7 @@ class CertificateItem(OrderItem):
@property
def single_item_receipt_template(self):
if self.mode == 'verified':
if self.mode in ('verified', 'professional'):
return 'shoppingcart/verified_cert_receipt.html'
else:
return super(CertificateItem, self).single_item_receipt_template
......
......@@ -222,7 +222,7 @@ class ItemizedPurchaseReportTest(ModuleStoreTestCase):
self.CORRECT_CSV = dedent("""
Purchase Time,Order ID,Status,Quantity,Unit Cost,Total Cost,Currency,Description,Comments
{time_str},1,purchased,1,40,40,usd,Registration for Course: Robot Super Course,Ba\xc3\xbc\xe5\x8c\x85
{time_str},1,purchased,1,40,40,usd,"Certificate of Achievement, verified cert for course Robot Super Course",
{time_str},1,purchased,1,40,40,usd,verified cert for course Robot Super Course,
""".format(time_str=str(self.now)))
def test_purchased_items_btw_dates(self):
......
......@@ -74,18 +74,27 @@ class VerifyView(View):
# bookkeeping-wise just to start over.
progress_state = "start"
modes_dict = CourseMode.modes_for_course_dict(course_id)
verify_mode = modes_dict.get('verified', None)
# we prefer professional over verify
current_mode = CourseMode.verified_mode_for_course(course_id)
# if the course doesn't have a verified mode, we want to kick them
# from the flow
if not verify_mode:
if not current_mode:
return redirect(reverse('dashboard'))
if course_id.to_deprecated_string() in request.session.get("donation_for_course", {}):
chosen_price = request.session["donation_for_course"][course_id.to_deprecated_string()]
else:
chosen_price = verify_mode.min_price
chosen_price = current_mode.min_price
course = modulestore().get_course(course_id)
if current_mode.suggested_prices != '':
suggested_prices = [
decimal.Decimal(price)
for price in current_mode.suggested_prices.split(",")
]
else:
suggested_prices = []
context = {
"progress_state": progress_state,
"user_full_name": request.user.profile.name,
......@@ -95,15 +104,13 @@ class VerifyView(View):
"course_org": course.display_org_with_default,
"course_num": course.display_number_with_default,
"purchase_endpoint": get_purchase_endpoint(),
"suggested_prices": [
decimal.Decimal(price)
for price in verify_mode.suggested_prices.split(",")
],
"currency": verify_mode.currency.upper(),
"suggested_prices": suggested_prices,
"currency": current_mode.currency.upper(),
"chosen_price": chosen_price,
"min_price": verify_mode.min_price,
"min_price": current_mode.min_price,
"upgrade": upgrade == u'True',
"can_audit": "audit" in modes_dict,
"can_audit": CourseMode.mode_for_course(course_id, 'audit') is not None,
"modes_dict": CourseMode.modes_for_course_dict(course_id),
}
return render_to_response('verify_student/photo_verification.html', context)
......@@ -124,19 +131,20 @@ class VerifiedView(View):
if CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == ('verified', True):
return redirect(reverse('dashboard'))
modes_dict = CourseMode.modes_for_course_dict(course_id)
verify_mode = modes_dict.get('verified', None)
if verify_mode is None:
return redirect(reverse('dashboard'))
# we prefer professional over verify
current_mode = CourseMode.verified_mode_for_course(course_id)
chosen_price = request.session.get(
"donation_for_course",
{}
).get(
course_id.to_deprecated_string(),
verify_mode.min_price
)
# if the course doesn't have a verified mode, we want to kick them
# from the flow
if not current_mode:
return redirect(reverse('dashboard'))
if course_id.to_deprecated_string() in request.session.get("donation_for_course", {}):
chosen_price = request.session["donation_for_course"][course_id.to_deprecated_string()]
else:
chosen_price = current_mode.min_price
course = modulestore().get_course(course_id)
context = {
......@@ -146,11 +154,12 @@ class VerifiedView(View):
"course_org": course.display_org_with_default,
"course_num": course.display_number_with_default,
"purchase_endpoint": get_purchase_endpoint(),
"currency": verify_mode.currency.upper(),
"currency": current_mode.currency.upper(),
"chosen_price": chosen_price,
"create_order_url": reverse("verify_student_create_order"),
"upgrade": upgrade == u'True',
"can_audit": "audit" in modes_dict,
"modes_dict": modes_dict,
}
return render_to_response('verify_student/verified.html', context)
......@@ -185,19 +194,24 @@ def create_order(request):
donation_for_course[course_id] = amount
request.session['donation_for_course'] = donation_for_course
verified_mode = CourseMode.modes_for_course_dict(course_id).get('verified', None)
# prefer professional mode over verified_mode
current_mode = CourseMode.verified_mode_for_course(course_id)
if current_mode.slug == 'professional':
amount = current_mode.min_price
# make sure this course has a verified mode
if not verified_mode:
if not current_mode:
return HttpResponseBadRequest(_("This course doesn't support verified certificates"))
if amount < verified_mode.min_price:
if amount < current_mode.min_price:
return HttpResponseBadRequest(_("No selected price or selected price is below minimum."))
# I know, we should check this is valid. All kinds of stuff missing here
cart = Order.get_cart_for_user(request.user)
cart.clear()
CertificateItem.add_to_order(cart, course_id, amount, 'verified')
enrollment_mode = current_mode.slug
CertificateItem.add_to_order(cart, course_id, amount, enrollment_mode)
params = get_signed_purchase_params(cart)
......@@ -288,12 +302,20 @@ def show_requirements(request, course_id):
"""
Show the requirements necessary for the verification flow.
"""
# TODO: seems borked for professional; we're told we need to take photos even if there's a pending verification
course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
upgrade = request.GET.get('upgrade', False)
if CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == ('verified', True):
return redirect(reverse('dashboard'))
if SoftwareSecurePhotoVerification.user_has_valid_or_pending(request.user):
return redirect(
reverse('verify_student_verified',
kwargs={'course_id': course_id.to_deprecated_string()}) + "?upgrade={}".format(upgrade)
)
upgrade = request.GET.get('upgrade', False)
course = modulestore().get_course(course_id)
modes_dict = CourseMode.modes_for_course_dict(course_id)
context = {
"course_id": course_id.to_deprecated_string(),
"course_modes_choose_url": reverse("course_modes_choose", kwargs={'course_id': course_id.to_deprecated_string()}),
......@@ -303,6 +325,7 @@ def show_requirements(request, course_id):
"course_num": course.display_number_with_default,
"is_not_active": not request.user.is_active,
"upgrade": upgrade == u'True',
"modes_dict": modes_dict,
}
return render_to_response("verify_student/show_requirements.html", context)
......
......@@ -177,12 +177,13 @@
<dt class="faq-question">${_("What do you do with this picture?")}</dt>
<dd class="faq-answer">${_("We only use it to verify your identity. It is not displayed anywhere.")}</dd>
<dt class="faq-question">${_("What if my camera isn't working?")}</dt>
%if upgrade:
<dd class="faq-answer">${_("You can always continue to audit the course without verifying.")}</dd>
%else:
<dd class="faq-answer">${_("You can always {a_start} audit the course for free {a_end} without verifying.").format(a_start='<a rel="external" href="{}">'.format(course_modes_choose_url), a_end="</a>")}</dd>
%if "professional" not in modes_dict:
<dt class="faq-question">${_("What if my camera isn't working?")}</dt>
%if upgrade:
<dd class="faq-answer">${_("You can always continue to audit the course without verifying.")}</dd>
%else:
<dd class="faq-answer">${_("You can always {a_start} audit the course for free {a_end} without verifying.").format(a_start='<a rel="external" href="{}">'.format(course_modes_choose_url), a_end="</a>")}</dd>
%endif
%endif
</dl>
</div>
......@@ -366,6 +367,7 @@
</ul>
</li>
%if len(suggested_prices) > 0:
<li class="review-task review-task-contribution">
<h4 class="title">${_("Check Your Contribution Level")}</h4>
......@@ -376,12 +378,28 @@
<%include file="/course_modes/_contribution.html" args="suggested_prices=suggested_prices, currency=currency, chosen_price=chosen_price, min_price=min_price"/>
</li>
%else:
<li class="review-task review-task-contribution">
<h4 class="title">${_("Your Course Total")}</h4>
<div class="copy">
<p>${_("To complete your registration, you will need to pay:")}</p>
</div>
<ul class="list-fields contribution-options">
<li class="field contribution-option">
<span class="deco-denomination">$</span>
<span class="label-value">${chosen_price}</span>
<span class="denomination-name">${currency}</span>
</label>
</li>
</ul>
</li>
%endif
</ol>
</div>
<nav class="nav-wizard">
<div class="prompt-verify">
<h3 class="title">Before proceeding, please confirm that your details match</h3>
<h3 class="title">${_("Before proceeding, please confirm that your details match")}</h3>
<p class="copy"> ${_("Once you verify your details match the requirements, you can move on to step 4, payment on our secure server.")}</p>
......
......@@ -85,8 +85,11 @@ $(document).ready(function() {
</div>
<nav class="nav-wizard is-ready">
%if "professional" in modes_dict:
<span class="help help-inline price-value">${_("Your Course Total is $ ")} <strong>${chosen_price}</strong></span>
%else:
<span class="help help-inline price-value">${_("You have decided to pay $ ")} <strong>${chosen_price}</strong></span>
%endif
<ol class="wizard-steps">
<li class="wizard-step step-proceed">
......
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