def test_fetch_user_case_sens(): """fetch_user should be able to fetch a User with a case-insensitive filter""" email = "*****@*****.**" user = UserFactory.create(email=email) upper_email = email.upper() with pytest.raises(User.DoesNotExist): fetch_user(upper_email, ignore_case=False) assert fetch_user(upper_email, ignore_case=True) == user
def test_fetch_user(prop, value, db_value): """ fetch_user should return a User that matches a provided value which represents an id, email, or username """ user = UserFactory.create(**{prop: db_value or value}) found_user = fetch_user(value) assert user == found_user
def handle(self, *args, **options): """Handle command execution""" user = fetch_user(options["user"]) keep_failed_enrollments = options["keep_failed_enrollments"] enrollment, _ = self.fetch_enrollment(user, options) if options["program"]: program_enrollment, run_enrollments = deactivate_program_enrollment( enrollment, change_status=ENROLL_CHANGE_STATUS_REFUNDED, keep_failed_enrollments=keep_failed_enrollments, ) else: program_enrollment = None run_enrollments = [] run_enrollment = deactivate_run_enrollment( enrollment, change_status=ENROLL_CHANGE_STATUS_REFUNDED, keep_failed_enrollments=keep_failed_enrollments, ) if run_enrollment: run_enrollments.append(run_enrollment) if program_enrollment or run_enrollments: success_msg = "Refunded enrollments for user: {} ({})\nEnrollments affected: {}".format( enrollment.user.username, enrollment.user.email, enrollment_summaries( filter(bool, [program_enrollment] + run_enrollments)), ) if enrollment.order: enrollment.order.status = Order.REFUNDED enrollment.order.save_and_log(None) success_msg += "\nOrder status set to '{}' (order id: {})".format( enrollment.order.status, enrollment.order.id) else: self.stdout.write( self.style.WARNING( "The given enrollment is not associated with an order, so no order status will be changed." )) self.stdout.write(self.style.SUCCESS(success_msg)) else: self.stdout.write( self.style.ERROR( "Failed to refund the enrollment – 'for' user: {} ({}) from course / program ({})\n" .format(user.username, user.email, options["run"] or options["program"])))
def handle(self, *args, **options): """Handle command execution""" user = fetch_user(options["user"]) from_courseware_id = options["from_run"] to_courseware_id = options["to_run"] try: from_enrollment, to_enrollment = defer_enrollment( user, from_courseware_id, to_courseware_id, keep_failed_enrollments=options["keep_failed_enrollments"], force=options["force"], ) except ObjectDoesNotExist as exc: if isinstance(exc, CourseRunEnrollment.DoesNotExist): message = "'from' course run enrollment does not exist ({})".format( from_courseware_id) elif isinstance(exc, CourseRun.DoesNotExist): message = "'to' course does not exist ({})".format( to_courseware_id) else: message = str(exc) raise CommandError(message) except ValidationError as exc: raise CommandError("Invalid enrollment deferral - {}".format(exc)) else: if not to_enrollment: raise CommandError( "Failed to create/update the target enrollment ({})". format(to_courseware_id)) self.stdout.write( self.style.SUCCESS("Deferred enrollment for user: {}\n" "Enrollment deactivated: {}\n" "Enrollment created/updated: {}".format( user, enrollment_summary(from_enrollment), enrollment_summary(to_enrollment), )))
def handle(self, *args, **options): # pylint: disable=too-many-locals """Handle command execution""" user = fetch_user(options["user"]) if options["user"] else None program = options.get("program") run = options.get("run") revoke = options.get("revoke") include_program_courses = options.get("include_program_courses") if program and run: raise CommandError( "Either 'program' or 'run' should be provided, not both.") if not program and not run: raise CommandError("Either 'program' or 'run' must be provided.") if (program or run) and not user: raise CommandError("A valid user must be provided.") updated = False if program: updated = revoke_program_certificate( user=user, readable_id=program, revoke_state=revoke, include_program_courses=include_program_courses, ) elif run: updated = revoke_course_run_certificate(user=user, courseware_id=run, revoke_state=revoke) if updated: msg = "Certificate for {} has been {}".format( "run: {}".format(run) if run else "program: {}".format(program), "revoked" if revoke else "un-revoked", ) self.stdout.write(self.style.SUCCESS(msg)) else: self.stdout.write(self.style.WARNING("No changes made."))
def handle(self, *args, **options): """Handle command execution""" user = fetch_user(options["user"]) run = CourseRun.objects.filter(courseware_id=options["run"]).first() if run is None: raise CommandError( "Could not find course run with courseware_id={}".format( options["run"])) product = Product.objects.filter( courseruns__courseware_id=options["run"]).first() if product is None: raise CommandError( "No product found for that course with courseware_id={}". format(options["run"])) coupon = Coupon.objects.filter(coupon_code=options["code"]).first() if not coupon: raise CommandError("That enrollment code {} does not exist".format( options["code"])) # Check if the coupon is valid for the product coupon_version = best_coupon_for_product(product, user, code=coupon.coupon_code) if coupon_version is None: raise CommandError({ "coupons": "Enrollment code {} is invalid for course run {}".format( options["code"], options["run"]) }) # Fetch the latest product version. product_version = latest_product_version(product) # Calculate the total paid price after applying coupon. total_price_paid = get_product_version_price_with_discount( coupon_version=coupon_version, product_version=product_version) with transaction.atomic(): # Create an order. order = Order.objects.create( status=Order.FULFILLED, purchaser=user, total_price_paid=total_price_paid, ) successful_enrollments, edx_request_success = create_run_enrollments( user, [run], keep_failed_enrollments=options["keep_failed_enrollments"], order=order, ) if not successful_enrollments: raise CommandError("Failed to create the enrollment record") ProductCouponAssignment.objects.filter( email__iexact=user.email, redeemed=False, product_coupon__coupon=coupon).update(redeemed=True) self.stdout.write( self.style.SUCCESS( "Enrollment created for user {} in {} (edX enrollment success: {})" .format(user, options["run"], edx_request_success))) line = Line.objects.create(order=order, product_version=product_version, quantity=1) redeem_coupon(coupon_version=coupon_version, order=order) self.stdout.write( self.style.SUCCESS( "Order {} with line {} is created for user {} ".format( order, line, user)))
def handle(self, *args, **options): from_user = fetch_user(options["from_user"]) to_user = fetch_user(options["to_user"]) keep_failed_enrollments = options["keep_failed_enrollments"] enrollment, enrolled_obj = self.fetch_enrollment(from_user, options) if options["program"]: to_user_existing_enrolled_run_ids = CourseRunEnrollment.get_program_run_enrollments( user=to_user, program=enrolled_obj).values_list("run__courseware_id", flat=True) if len(to_user_existing_enrolled_run_ids) > 0: raise CommandError( "'to' user is already enrolled in program runs ({})". format(list(to_user_existing_enrolled_run_ids))) new_program_enrollment, new_run_enrollments = self.create_program_enrollment( enrollment, to_user=to_user, keep_failed_enrollments=keep_failed_enrollments, ) if new_program_enrollment and new_run_enrollments: deactivate_program_enrollment( enrollment, change_status=ENROLL_CHANGE_STATUS_TRANSFERRED, keep_failed_enrollments=keep_failed_enrollments, ) else: new_program_enrollment = None new_run_enrollment = self.create_run_enrollment( enrollment, to_user=to_user, keep_failed_enrollments=keep_failed_enrollments, ) new_run_enrollments = [] if new_run_enrollment: new_run_enrollments.append(new_run_enrollment) deactivate_run_enrollment( enrollment, change_status=ENROLL_CHANGE_STATUS_TRANSFERRED, keep_failed_enrollments=keep_failed_enrollments, ) if new_program_enrollment or new_run_enrollments: self.stdout.write( self.style.SUCCESS( "Transferred enrollment – 'from' user: {} ({}), 'to' user: {} ({})\n" "Enrollments created/updated: {}".format( from_user.username, from_user.email, to_user.username, to_user.email, enrollment_summaries( filter(bool, [new_program_enrollment] + new_run_enrollments)), ))) else: self.stdout.write( self.style.ERROR( "Failed to transfer enrollment – 'from' user: {} ({}), 'to' user: {} ({})\n" .format( from_user.username, from_user.email, to_user.username, to_user.email, )))
def test_fetch_user_fail(): """fetch_user should raise an exception if a matching User was not found""" with pytest.raises(User.DoesNotExist): fetch_user("*****@*****.**")
def handle(self, *args, **options): # pylint: disable=too-many-locals,too-many-branches """Handle command execution""" # Grade override for all users for the course run. Disallowed. if options["grade"] is not None and not options["user"]: raise CommandError( "No user supplied with override grade. Overwrite of grade is not supported for all users. Grade should only be supplied when a specific user is targeted." ) try: run = CourseRun.objects.get(courseware_id=options["run"]) except CourseRun.DoesNotExist: raise CommandError( "Could not find run with courseware_id={}".format( options["run"])) now = now_in_utc() if not options.get("force") and (run.end_date is None or run.end_date > now): raise CommandError( "The given course run has not yet finished, so the course grades should not be " "considered final (courseware_id={}, end_date={}).\n" "Add the -f/--force flag if grades/certificates should be synced anyway." .format( options["run"], "None" if run.end_date is None else run.end_date.isoformat(), )) user = fetch_user(options["user"]) if options["user"] else None override_grade = None should_update = options["update"] if options["grade"] is not None: override_grade = float(options["grade"]) if override_grade and (override_grade < 0.0 or override_grade > 1.0): raise CommandError( "Invalid value for grade. Allowed range: 0.0 - 1.0") edx_grade_user_iter = get_edx_grades_with_users(run, user=user) results = [] for edx_grade, user in edx_grade_user_iter: course_run_grade, created_grade, updated_grade = ensure_course_run_grade( user=user, course_run=run, edx_grade=edx_grade, should_update=should_update, ) if override_grade is not None: course_run_grade.grade = override_grade course_run_grade.passed = bool(override_grade) course_run_grade.letter_grade = None course_run_grade.set_by_admin = True course_run_grade.save_and_log(None) _, created_cert, deleted_cert = process_course_run_grade_certificate( course_run_grade=course_run_grade) if created_grade: grade_status = "created" elif updated_grade: grade_status = "updated" else: grade_status = "already exists" grade_summary = ["passed: {}".format(course_run_grade.passed)] if override_grade is not None: grade_summary.append("value override: {}".format( course_run_grade.grade)) if created_cert: cert_status = "created" elif deleted_cert: cert_status = "deleted" elif course_run_grade.passed: cert_status = "already exists" else: cert_status = "ignored" result_summary = "Grade: {} ({}), Certificate: {}".format( grade_status, ", ".join(grade_summary), cert_status) results.append( "Processed user {} ({}) in course run {}. Result - {}".format( user.username, user.email, run.courseware_id, result_summary)) for result in results: self.stdout.write(self.style.SUCCESS(result))