예제 #1
0
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
예제 #2
0
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
예제 #3
0
    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)
예제 #4
0
    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)
예제 #5
0
    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)
예제 #6
0
    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)
예제 #7
0
    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)
예제 #8
0
    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)
예제 #9
0
    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)
예제 #10
0
    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)
예제 #11
0
    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)
예제 #12
0
    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)