def checkout_with_shoppingcart(request, user, course_key, course_mode, amount): """ Create an order and trigger checkout using shoppingcart.""" cart = Order.get_cart_for_user(user) cart.clear() enrollment_mode = course_mode.slug CertificateItem.add_to_order(cart, course_key, amount, enrollment_mode) # Change the order's status so that we don't accidentally modify it later. # We need to do this to ensure that the parameters we send to the payment system # match what we store in the database. # (Ordinarily we would do this client-side when the user submits the form, but since # the JavaScript on this page does that immediately, we make the change here instead. # This avoids a second AJAX call and some additional complication of the JavaScript.) # If a user later re-enters the verification / payment flow, she will create a new order. cart.start_purchase() callback_url = request.build_absolute_uri( reverse("shoppingcart.views.postpay_callback")) payment_data = { 'payment_processor_name': settings.CC_PROCESSOR_NAME, 'payment_page_url': get_purchase_endpoint(), 'payment_form_data': get_signed_purchase_params( cart, callback_url=callback_url, extra_data=[unicode(course_key), course_mode.slug]), } return payment_data
def checkout_with_shoppingcart(request, user, course_key, course_mode, amount): """ Create an order and trigger checkout using shoppingcart.""" cart = Order.get_cart_for_user(user) cart.clear() enrollment_mode = course_mode.slug CertificateItem.add_to_order(cart, course_key, amount, enrollment_mode) # Change the order's status so that we don't accidentally modify it later. # We need to do this to ensure that the parameters we send to the payment system # match what we store in the database. # (Ordinarily we would do this client-side when the user submits the form, but since # the JavaScript on this page does that immediately, we make the change here instead. # This avoids a second AJAX call and some additional complication of the JavaScript.) # If a user later re-enters the verification / payment flow, she will create a new order. cart.start_purchase() callback_url = request.build_absolute_uri( reverse("shoppingcart.views.postpay_callback") ) payment_data = { 'payment_processor_name': settings.CC_PROCESSOR_NAME, 'payment_page_url': get_purchase_endpoint(), 'payment_form_data': get_signed_purchase_params( cart, callback_url=callback_url, extra_data=[unicode(course_key), course_mode.slug] ), } return payment_data
def get(self, request, course_id): """ Handle the case where we have a get request """ upgrade = request.GET.get('upgrade', False) course_id = CourseKey.from_string(course_id) 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) # 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 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"][unicode( course_id)] else: chosen_price = current_mode.min_price course = modulestore().get_course(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()}), "course_name": course.display_name_with_default, "course_org": course.display_org_with_default, "course_num": course.display_number_with_default, "purchase_endpoint": get_purchase_endpoint(), "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, # TODO (ECOM-16): Remove once the AB test completes "autoreg": request.session.get('auto_register', False), } return render_to_response('verify_student/verified.html', context)
def get(self, request, course_id): """ Handle the case where we have a get request """ upgrade = request.GET.get('upgrade', False) course_id = CourseKey.from_string(course_id) 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) # 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 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"][unicode(course_id)] else: chosen_price = current_mode.min_price course = modulestore().get_course(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()}), "course_name": course.display_name_with_default, "course_org": course.display_org_with_default, "course_num": course.display_number_with_default, "purchase_endpoint": get_purchase_endpoint(), "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, # TODO (ECOM-16): Remove once the AB test completes "autoreg": request.session.get('auto_register', False), } return render_to_response('verify_student/verified.html', context)
def get(self, request, course_id): """ Displays edera payment process """ course_id = CourseKey.from_string(course_id) # 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 current_mode: return redirect(reverse('dashboard')) 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 = [] chosen_price = suggested_prices[0] context = { "user_full_name": request.user.profile.name, "course_id": course_id.to_deprecated_string(), "course_modes_choose_url": reverse('course_modes_choose', kwargs={'course_id': course_id.to_deprecated_string()}), "course_name": course.display_name_with_default, "course_org": course.display_org_with_default, "course_num": course.display_number_with_default, "purchase_endpoint": get_purchase_endpoint(), "suggested_prices": suggested_prices, "currency": current_mode.currency.upper(), "chosen_price": chosen_price, "min_price": current_mode.min_price, "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/edera_choose_and_pay.html', context)
def get( self, request, course_id, always_show_payment=False, current_step=None, message=FIRST_TIME_VERIFY_MSG ): """Render the pay/verify requirements page. Arguments: request (HttpRequest): The request object. course_id (unicode): The ID of the course the user is trying to enroll in. Keyword Arguments: always_show_payment (bool): If True, show the payment steps even if the user has already paid. This is useful for users returning to the flow after paying. current_step (string): The current step in the flow. message (string): The messaging to display. Returns: HttpResponse Raises: Http404: The course does not exist or does not have a verified mode. """ # Parse the course key # The URL regex should guarantee that the key format is valid. course_key = CourseKey.from_string(course_id) course = modulestore().get_course(course_key) # Verify that the course exists and has a verified mode if course is None: log.warn(u"No course specified for verification flow request.") raise Http404 # Check whether the user has access to this course # based on country access rules. redirect_url = embargo_api.redirect_if_blocked( course_key, user=request.user, ip_address=get_ip(request), url=request.path ) if redirect_url: return redirect(redirect_url) expired_verified_course_mode, unexpired_paid_course_mode = self._get_expired_verified_and_paid_mode(course_key) # Check that the course has an unexpired paid mode if unexpired_paid_course_mode is not None: if CourseMode.is_verified_mode(unexpired_paid_course_mode): log.info( u"Entering verified workflow for user '%s', course '%s', with current step '%s'.", request.user.id, course_id, current_step ) elif expired_verified_course_mode is not None: # Check if there is an *expired* verified course mode; # if so, we should show a message explaining that the verification # deadline has passed. log.info(u"Verification deadline for '%s' has passed.", course_id) context = { 'course': course, 'deadline': ( get_default_time_display(expired_verified_course_mode.expiration_datetime) if expired_verified_course_mode.expiration_datetime else "" ) } return render_to_response("verify_student/missed_verification_deadline.html", context) else: # Otherwise, there has never been a verified/paid mode, # so return a page not found response. log.warn( u"No paid/verified course mode found for course '%s' for verification/payment flow request", course_id ) raise Http404 # Check whether the user has verified, paid, and enrolled. # A user is considered "paid" if he or she has an enrollment # with a paid course mode (such as "verified"). # For this reason, every paid user is enrolled, but not # every enrolled user is paid. # If the course mode is not verified(i.e only paid) then already_verified is always True already_verified = self._check_already_verified(request.user) \ if CourseMode.is_verified_mode(unexpired_paid_course_mode) else True already_paid, is_enrolled = self._check_enrollment(request.user, course_key) # Redirect the user to a more appropriate page if the # messaging won't make sense based on the user's # enrollment / payment / verification status. redirect_response = self._redirect_if_necessary( message, already_verified, already_paid, is_enrolled, course_key ) if redirect_response is not None: return redirect_response display_steps = self._display_steps( always_show_payment, already_verified, already_paid, unexpired_paid_course_mode ) requirements = self._requirements(display_steps, request.user.is_active) if current_step is None: current_step = display_steps[0]['name'] # Allow the caller to skip the first page # This is useful if we want the user to be able to # use the "back" button to return to the previous step. # This parameter should only work for known skip-able steps if request.GET.get('skip-first-step') and current_step in self.SKIP_STEPS: display_step_names = [step['name'] for step in display_steps] current_step_idx = display_step_names.index(current_step) if (current_step_idx + 1) < len(display_steps): current_step = display_steps[current_step_idx + 1]['name'] courseware_url = "" if not course.start or course.start < datetime.datetime.today().replace(tzinfo=UTC): courseware_url = reverse( 'course_root', kwargs={'course_id': unicode(course_key)} ) full_name = ( request.user.profile.name if request.user.profile.name else "" ) # If the user set a contribution amount on another page, # use that amount to pre-fill the price selection form. contribution_amount = request.session.get( 'donation_for_course', {} ).get(unicode(course_key), '') # Remember whether the user is upgrading # so we can fire an analytics event upon payment. request.session['attempting_upgrade'] = (message == self.UPGRADE_MSG) # Determine the photo verification status verification_good_until = self._verification_valid_until(request.user) # Render the top-level page context = { 'contribution_amount': contribution_amount, 'course': course, 'course_key': unicode(course_key), 'course_mode': unexpired_paid_course_mode, 'courseware_url': courseware_url, 'current_step': current_step, 'disable_courseware_js': True, 'display_steps': display_steps, 'is_active': json.dumps(request.user.is_active), 'message_key': message, 'platform_name': settings.PLATFORM_NAME, 'purchase_endpoint': get_purchase_endpoint(), 'requirements': requirements, 'user_full_name': full_name, 'verification_deadline': ( get_default_time_display(unexpired_paid_course_mode.expiration_datetime) if unexpired_paid_course_mode.expiration_datetime else "" ), 'already_verified': already_verified, 'verification_good_until': verification_good_until, } return render_to_response("verify_student/pay_and_verify.html", context)
def get(self, request, course_id): """ Displays the main verification view, which contains three separate steps: - Taking the standard face photo - Taking the id photo - Confirming that the photos and payment price are correct before proceeding to payment """ upgrade = request.GET.get('upgrade', False) course_id = CourseKey.from_string(course_id) # If the user has already been verified within the given time period, # redirect straight to the payment -- no need to verify again. 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)) elif CourseEnrollment.enrollment_mode_for_user( request.user, course_id) == ('verified', True): return redirect(reverse('dashboard')) else: # If they haven't completed a verification attempt, we have to # restart with a new one. We can't reuse an older one because we # won't be able to show them their encrypted photo_id -- it's easier # bookkeeping-wise just to start over. progress_state = "start" # 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 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"][unicode( course_id)] else: 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, "course_id": course_id.to_deprecated_string(), "course_modes_choose_url": reverse('course_modes_choose', kwargs={'course_id': course_id.to_deprecated_string()}), "course_name": course.display_name_with_default, "course_org": course.display_org_with_default, "course_num": course.display_number_with_default, "purchase_endpoint": get_purchase_endpoint(), "suggested_prices": suggested_prices, "currency": current_mode.currency.upper(), "chosen_price": chosen_price, "min_price": current_mode.min_price, "upgrade": upgrade == u'True', "can_audit": CourseMode.mode_for_course(course_id, 'audit') is not None, "modes_dict": CourseMode.modes_for_course_dict(course_id), "retake": request.GET.get('retake', False), } return render_to_response('verify_student/photo_verification.html', context)
def get(self, request, course_id): """ Displays the main verification view, which contains three separate steps: - Taking the standard face photo - Taking the id photo - Confirming that the photos and payment price are correct before proceeding to payment """ upgrade = request.GET.get('upgrade', False) course_id = CourseKey.from_string(course_id) # If the user has already been verified within the given time period, # redirect straight to the payment -- no need to verify again. 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) ) elif CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == ('verified', True): return redirect(reverse('dashboard')) else: # If they haven't completed a verification attempt, we have to # restart with a new one. We can't reuse an older one because we # won't be able to show them their encrypted photo_id -- it's easier # bookkeeping-wise just to start over. progress_state = "start" # 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 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"][unicode(course_id)] else: 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, "course_id": course_id.to_deprecated_string(), "course_modes_choose_url": reverse('course_modes_choose', kwargs={'course_id': course_id.to_deprecated_string()}), "course_name": course.display_name_with_default, "course_org": course.display_org_with_default, "course_num": course.display_number_with_default, "purchase_endpoint": get_purchase_endpoint(), "suggested_prices": suggested_prices, "currency": current_mode.currency.upper(), "chosen_price": chosen_price, "min_price": current_mode.min_price, "upgrade": upgrade == u'True', "can_audit": CourseMode.mode_for_course(course_id, 'audit') is not None, "modes_dict": CourseMode.modes_for_course_dict(course_id), "retake": request.GET.get('retake', False), } return render_to_response('verify_student/photo_verification.html', context)
def get(self, request, course_id, always_show_payment=False, current_step=None, message=FIRST_TIME_VERIFY_MSG): """Render the pay/verify requirements page. Arguments: request (HttpRequest): The request object. course_id (unicode): The ID of the course the user is trying to enroll in. Keyword Arguments: always_show_payment (bool): If True, show the payment steps even if the user has already paid. This is useful for users returning to the flow after paying. current_step (string): The current step in the flow. message (string): The messaging to display. Returns: HttpResponse Raises: Http404: The course does not exist or does not have a verified mode. """ # Parse the course key # The URL regex should guarantee that the key format is valid. course_key = CourseKey.from_string(course_id) course = modulestore().get_course(course_key) # Verify that the course exists and has a verified mode if course is None: raise Http404 # Verify that the course has a verified mode course_mode = CourseMode.verified_mode_for_course(course_key) if course_mode is None: raise Http404 # Check whether the user has verified, paid, and enrolled. # A user is considered "paid" if he or she has an enrollment # with a paid course mode (such as "verified"). # For this reason, every paid user is enrolled, but not # every enrolled user is paid. already_verified = self._check_already_verified(request.user) already_paid, is_enrolled = self._check_enrollment( request.user, course_key) # Redirect the user to a more appropriate page if the # messaging won't make sense based on the user's # enrollment / payment / verification status. redirect_response = self._redirect_if_necessary( message, already_verified, already_paid, is_enrolled, course_key) if redirect_response is not None: return redirect_response display_steps = self._display_steps(always_show_payment, already_verified, already_paid) requirements = self._requirements(display_steps, request.user.is_active) if current_step is None: current_step = display_steps[0]['name'] # Allow the caller to skip the first page # This is useful if we want the user to be able to # use the "back" button to return to the previous step. # This parameter should only work for known skip-able steps if request.GET.get( 'skip-first-step') and current_step in self.SKIP_STEPS: display_step_names = [step['name'] for step in display_steps] current_step_idx = display_step_names.index(current_step) if (current_step_idx + 1) < len(display_steps): current_step = display_steps[current_step_idx + 1]['name'] courseware_url = "" if not course.start or course.start < datetime.datetime.today( ).replace(tzinfo=UTC): courseware_url = reverse('course_root', kwargs={'course_id': unicode(course_key)}) full_name = (request.user.profile.name if request.user.profile.name else "") # If the user set a contribution amount on another page, # use that amount to pre-fill the price selection form. contribution_amount = request.session.get('donation_for_course', {}).get( unicode(course_key), '') # Render the top-level page context = { 'user_full_name': full_name, 'course': course, 'course_key': unicode(course_key), 'course_mode': course_mode, 'courseware_url': courseware_url, 'current_step': current_step, 'disable_courseware_js': True, 'display_steps': display_steps, 'contribution_amount': contribution_amount, 'is_active': request.user.is_active, 'messages': self._messages(message, course.display_name, course_mode, requirements), 'message_key': message, 'platform_name': settings.PLATFORM_NAME, 'purchase_endpoint': get_purchase_endpoint(), 'requirements': requirements, } return render_to_response("verify_student/pay_and_verify.html", context)
def get( self, request, course_id, always_show_payment=False, current_step=None, message=FIRST_TIME_VERIFY_MSG ): """Render the pay/verify requirements page. Arguments: request (HttpRequest): The request object. course_id (unicode): The ID of the course the user is trying to enroll in. Keyword Arguments: always_show_payment (bool): If True, show the payment steps even if the user has already paid. This is useful for users returning to the flow after paying. current_step (string): The current step in the flow. message (string): The messaging to display. Returns: HttpResponse Raises: Http404: The course does not exist or does not have a verified mode. """ # Parse the course key # The URL regex should guarantee that the key format is valid. course_key = CourseKey.from_string(course_id) course = modulestore().get_course(course_key) # Verify that the course exists and has a verified mode if course is None: log.warn(u"No course specified for verification flow request.") raise Http404 # Check whether the user has access to this course # based on country access rules. redirect_url = embargo_api.redirect_if_blocked( course_key, user=request.user, ip_address=get_ip(request), url=request.path ) if redirect_url: return redirect(redirect_url) expired_verified_course_mode, unexpired_paid_course_mode = self._get_expired_verified_and_paid_mode(course_key) # Check that the course has an unexpired paid mode if unexpired_paid_course_mode is not None: if CourseMode.is_verified_mode(unexpired_paid_course_mode): log.info( u"Entering verified workflow for user '%s', course '%s', with current step '%s'.", request.user.id, course_id, current_step ) elif expired_verified_course_mode is not None: # Check if there is an *expired* verified course mode; # if so, we should show a message explaining that the verification # deadline has passed. log.info(u"Verification deadline for '%s' has passed.", course_id) context = { 'course': course, 'deadline': ( get_default_time_display(expired_verified_course_mode.expiration_datetime) if expired_verified_course_mode.expiration_datetime else "" ) } return render_to_response("verify_student/missed_verification_deadline.html", context) else: # Otherwise, there has never been a verified/paid mode, # so return a page not found response. log.warn( u"No paid/verified course mode found for course '%s' for verification/payment flow request", course_id ) raise Http404 # Check whether the user has verified, paid, and enrolled. # A user is considered "paid" if he or she has an enrollment # with a paid course mode (such as "verified"). # For this reason, every paid user is enrolled, but not # every enrolled user is paid. # If the course mode is not verified(i.e only paid) then already_verified is always True already_verified = self._check_already_verified(request.user) \ if CourseMode.is_verified_mode(unexpired_paid_course_mode) else True already_paid, is_enrolled = self._check_enrollment(request.user, course_key) # Redirect the user to a more appropriate page if the # messaging won't make sense based on the user's # enrollment / payment / verification status. redirect_response = self._redirect_if_necessary( message, already_verified, already_paid, is_enrolled, course_key ) if redirect_response is not None: return redirect_response display_steps = self._display_steps( always_show_payment, already_verified, already_paid, unexpired_paid_course_mode ) requirements = self._requirements(display_steps, request.user.is_active) if current_step is None: current_step = display_steps[0]['name'] # Allow the caller to skip the first page # This is useful if we want the user to be able to # use the "back" button to return to the previous step. # This parameter should only work for known skip-able steps if request.GET.get('skip-first-step') and current_step in self.SKIP_STEPS: display_step_names = [step['name'] for step in display_steps] current_step_idx = display_step_names.index(current_step) if (current_step_idx + 1) < len(display_steps): current_step = display_steps[current_step_idx + 1]['name'] courseware_url = "" if not course.start or course.start < datetime.datetime.today().replace(tzinfo=UTC): courseware_url = reverse( 'course_root', kwargs={'course_id': unicode(course_key)} ) full_name = ( request.user.profile.name if request.user.profile.name else "" ) # If the user set a contribution amount on another page, # use that amount to pre-fill the price selection form. contribution_amount = request.session.get( 'donation_for_course', {} ).get(unicode(course_key), '') # Remember whether the user is upgrading # so we can fire an analytics event upon payment. request.session['attempting_upgrade'] = (message == self.UPGRADE_MSG) # Render the top-level page context = { 'contribution_amount': contribution_amount, 'course': course, 'course_key': unicode(course_key), 'course_mode': unexpired_paid_course_mode, 'courseware_url': courseware_url, 'current_step': current_step, 'disable_courseware_js': True, 'display_steps': display_steps, 'is_active': json.dumps(request.user.is_active), 'message_key': message, 'platform_name': settings.PLATFORM_NAME, 'purchase_endpoint': get_purchase_endpoint(), 'requirements': requirements, 'user_full_name': full_name, 'verification_deadline': ( get_default_time_display(unexpired_paid_course_mode.expiration_datetime) if unexpired_paid_course_mode.expiration_datetime else "" ), } return render_to_response("verify_student/pay_and_verify.html", context)
def get( self, request, course_id, always_show_payment=False, current_step=None, message=FIRST_TIME_VERIFY_MSG ): """Render the pay/verify requirements page. Arguments: request (HttpRequest): The request object. course_id (unicode): The ID of the course the user is trying to enroll in. Keyword Arguments: always_show_payment (bool): If True, show the payment steps even if the user has already paid. This is useful for users returning to the flow after paying. current_step (string): The current step in the flow. message (string): The messaging to display. Returns: HttpResponse Raises: Http404: The course does not exist or does not have a verified mode. """ # Parse the course key # The URL regex should guarantee that the key format is valid. course_key = CourseKey.from_string(course_id) course = modulestore().get_course(course_key) # Verify that the course exists and has a verified mode if course is None: raise Http404 # Verify that the course has a verified mode course_mode = CourseMode.verified_mode_for_course(course_key) if course_mode is None: raise Http404 # Check whether the user has verified, paid, and enrolled. # A user is considered "paid" if he or she has an enrollment # with a paid course mode (such as "verified"). # For this reason, every paid user is enrolled, but not # every enrolled user is paid. already_verified = self._check_already_verified(request.user) already_paid, is_enrolled = self._check_enrollment(request.user, course_key) # Redirect the user to a more appropriate page if the # messaging won't make sense based on the user's # enrollment / payment / verification status. redirect_response = self._redirect_if_necessary( message, already_verified, already_paid, is_enrolled, course_key ) if redirect_response is not None: return redirect_response display_steps = self._display_steps( always_show_payment, already_verified, already_paid ) requirements = self._requirements(display_steps, request.user.is_active) if current_step is None: current_step = display_steps[0]['name'] # Allow the caller to skip the first page # This is useful if we want the user to be able to # use the "back" button to return to the previous step. # This parameter should only work for known skip-able steps if request.GET.get('skip-first-step') and current_step in self.SKIP_STEPS: display_step_names = [step['name'] for step in display_steps] current_step_idx = display_step_names.index(current_step) if (current_step_idx + 1) < len(display_steps): current_step = display_steps[current_step_idx + 1]['name'] courseware_url = "" if not course.start or course.start < datetime.datetime.today().replace(tzinfo=UTC): courseware_url = reverse( 'course_root', kwargs={'course_id': unicode(course_key)} ) full_name = ( request.user.profile.name if request.user.profile.name else "" ) # If the user set a contribution amount on another page, # use that amount to pre-fill the price selection form. contribution_amount = request.session.get( 'donation_for_course', {} ).get(unicode(course_key), '') # Render the top-level page context = { 'user_full_name': full_name, 'course': course, 'course_key': unicode(course_key), 'course_mode': course_mode, 'courseware_url': courseware_url, 'current_step': current_step, 'disable_courseware_js': True, 'display_steps': display_steps, 'contribution_amount': contribution_amount, 'is_active': request.user.is_active, 'messages': self._messages( message, course.display_name, course_mode, requirements ), 'message_key': message, 'platform_name': settings.PLATFORM_NAME, 'purchase_endpoint': get_purchase_endpoint(), 'requirements': requirements, } return render_to_response("verify_student/pay_and_verify.html", context)
def get(self, request, course_id, always_show_payment=False, current_step=None, message=FIRST_TIME_VERIFY_MSG): """Render the pay/verify requirements page. Arguments: request (HttpRequest): The request object. course_id (unicode): The ID of the course the user is trying to enroll in. Keyword Arguments: always_show_payment (bool): If True, show the payment steps even if the user has already paid. This is useful for users returning to the flow after paying. current_step (string): The current step in the flow. message (string): The messaging to display. Returns: HttpResponse Raises: Http404: The course does not exist or does not have a verified mode. """ # Parse the course key # The URL regex should guarantee that the key format is valid. course_key = CourseKey.from_string(course_id) course = modulestore().get_course(course_key) # Verify that the course exists and has a verified mode if course is None: log.warn(u"No course specified for verification flow request.") raise Http404 # Verify that the course has a verified mode course_mode = CourseMode.verified_mode_for_course(course_key) if course_mode is None: log.warn( u"No verified course mode found for course '{course_id}' for verification flow request".format( course_id=course_id ) ) raise Http404 log.info( u"Entering verified workflow for user '{user}', course '{course_id}', with current step '{current_step}'.".format( user=request.user, course_id=course_id, current_step=current_step ) ) # Check whether the user has verified, paid, and enrolled. # A user is considered "paid" if he or she has an enrollment # with a paid course mode (such as "verified"). # For this reason, every paid user is enrolled, but not # every enrolled user is paid. already_verified = self._check_already_verified(request.user) already_paid, is_enrolled = self._check_enrollment(request.user, course_key) # Redirect the user to a more appropriate page if the # messaging won't make sense based on the user's # enrollment / payment / verification status. redirect_response = self._redirect_if_necessary( message, already_verified, already_paid, is_enrolled, course_key ) if redirect_response is not None: return redirect_response display_steps = self._display_steps(always_show_payment, already_verified, already_paid) requirements = self._requirements(display_steps, request.user.is_active) if current_step is None: current_step = display_steps[0]["name"] # Allow the caller to skip the first page # This is useful if we want the user to be able to # use the "back" button to return to the previous step. # This parameter should only work for known skip-able steps if request.GET.get("skip-first-step") and current_step in self.SKIP_STEPS: display_step_names = [step["name"] for step in display_steps] current_step_idx = display_step_names.index(current_step) if (current_step_idx + 1) < len(display_steps): current_step = display_steps[current_step_idx + 1]["name"] courseware_url = "" if not course.start or course.start < datetime.datetime.today().replace(tzinfo=UTC): courseware_url = reverse("course_root", kwargs={"course_id": unicode(course_key)}) full_name = request.user.profile.name if request.user.profile.name else "" # If the user set a contribution amount on another page, # use that amount to pre-fill the price selection form. contribution_amount = request.session.get("donation_for_course", {}).get(unicode(course_key), "") # Remember whether the user is upgrading # so we can fire an analytics event upon payment. request.session["attempting_upgrade"] = message == self.UPGRADE_MSG # Render the top-level page context = { "contribution_amount": contribution_amount, "course": course, "course_key": unicode(course_key), "course_mode": course_mode, "courseware_url": courseware_url, "current_step": current_step, "disable_courseware_js": True, "display_steps": display_steps, "is_active": json.dumps(request.user.is_active), "message_key": message, "platform_name": settings.PLATFORM_NAME, "purchase_endpoint": get_purchase_endpoint(), "requirements": requirements, "user_full_name": full_name, "verification_deadline": ( get_default_time_display(course_mode.expiration_datetime) if course_mode.expiration_datetime else "" ), } return render_to_response("verify_student/pay_and_verify.html", context)