def enroll_user(cls, enterprise_customer, user, course_mode, *course_ids): """ Enroll a single user in any number of courses using a particular course mode. Args: enterprise_customer: The EnterpriseCustomer which is sponsoring the enrollment user: The user who needs to be enrolled in the course course_mode: The mode with which the enrollment should be created *course_ids: An iterable containing any number of course IDs to eventually enroll the user in. Returns: Boolean: Whether or not enrollment succeeded for all courses specified """ enterprise_customer_user, __ = EnterpriseCustomerUser.objects.get_or_create( enterprise_customer=enterprise_customer, user_id=user.id) enrollment_client = EnrollmentApiClient() succeeded = True for course_id in course_ids: try: enrollment_client.enroll_user_in_course( user.username, course_id, course_mode) except HttpClientError as exc: # Check if user is already enrolled then we should ignore exception if cls.is_user_enrolled(user, course_id, course_mode): succeeded = True else: succeeded = False default_message = 'No error message provided' try: error_message = json.loads(exc.content.decode()).get( 'message', default_message) except ValueError: error_message = default_message logging.error( 'Error while enrolling user %(user)s: %(message)s', dict(user=user.username, message=error_message)) if succeeded: __, created = EnterpriseCourseEnrollment.objects.get_or_create( enterprise_customer_user=enterprise_customer_user, course_id=course_id, defaults={ 'source': EnterpriseEnrollmentSource.get_source( EnterpriseEnrollmentSource.MANUAL) }) if created: track_enrollment('admin-enrollment', user.id, course_id) return succeeded
def create_enterprise_enrollment(course_id, enterprise_customer_user_id): """ Create enterprise enrollment for user if course_id part of catalog for the ENT customer. """ enterprise_customer_user = EnterpriseCustomerUser.objects.get( id=enterprise_customer_user_id) # Prevent duplicate records from being created if possible # before we need to make a call to discovery if EnterpriseCourseEnrollment.objects.filter( enterprise_customer_user=enterprise_customer_user, course_id=course_id, ).exists(): LOGGER.info(("EnterpriseCourseEnrollment record exists for user %s " "on course %s. Exiting task."), enterprise_customer_user.user_id, course_id) return enterprise_customer = enterprise_customer_user.enterprise_customer if enterprise_customer.catalog_contains_course(course_id): LOGGER.info(("Creating EnterpriseCourseEnrollment for user %s " "on course %s for enterprise_customer %s"), enterprise_customer_user.user_id, course_id, enterprise_customer) # On Create we set the Source to be ENROLLMENT_TASK here. This Source # is generalized from being just a B2C Source type because it is possible # to reach this task before the EnterpriseCustomerEnrollment is created # depending on timing. # # We have made changes elsewhere to avoid this issue, but in the mean time # we believe a Source of ENROLLMENT_TASK is more clear. EnterpriseCourseEnrollment.objects.create( course_id=course_id, enterprise_customer_user=enterprise_customer_user, source=EnterpriseEnrollmentSource.get_source( EnterpriseEnrollmentSource.ENROLLMENT_TASK))
def handle(self, *args, **options): LOGGER.info("Command has started...") enterprise_customer_uuid_filter = options.get( 'enterprise_customer_uuid') records_created = 0 records_failed = 0 missing_enrollment_data = self._fetch_course_enrollment_data( enterprise_customer_uuid_filter) LOGGER.info('System has %s missing enrollments', len(missing_enrollment_data)) for item in missing_enrollment_data: course_exist_in_catalog = False user_id = item['user_id'] course_run_id = item['course_run_id'] enterprise_customer_uuid = item['enterprise_customer_uuid'] LOGGER.info( 'Trying to create the enrollment for user [%s] in course [%s] for enterprise customer [%s]', user_id, course_run_id, enterprise_customer_uuid) # pylint: disable=no-member enterprise_customer = EnterpriseCustomer.objects.get( uuid=enterprise_customer_uuid) try: LOGGER.info( 'Checking whether course [%s] exists in enterprise customer [%s] - [%s] catalog', course_run_id, enterprise_customer_uuid, enterprise_customer.name) course_exist_in_catalog = enterprise_customer.catalog_contains_course( course_run_id) except Exception as exc: # pylint: disable=broad-except records_failed += 1 LOGGER.warning( 'Course [%s] does not exist in EnterpriseCustomer [%s] due to this exception: [%s]', course_run_id, enterprise_customer.uuid, str(exc)) if course_exist_in_catalog: enterprise_customer_user = EnterpriseCustomerUser.objects.filter( enterprise_customer=enterprise_customer_uuid, user_id=user_id) # This is an extra check for preventing the exception. # We already have implemented the solution for this (soft deletion). if enterprise_customer_user.exists(): enterprise_customer_user = enterprise_customer_user.first() # pylint: disable=no-member __, created = EnterpriseCourseEnrollment.objects.get_or_create( enterprise_customer_user=enterprise_customer_user, course_id=course_run_id, defaults={ 'source': EnterpriseEnrollmentSource.get_source( EnterpriseEnrollmentSource.MANAGEMENT_COMMAND) }) if created: # if we have enrolled the user in a course then we should # active this record and inactive all the other records. enterprise_customer_user.active = True enterprise_customer_user.save() EnterpriseCustomerUser.inactivate_other_customers( user_id, enterprise_customer) records_created += 1 LOGGER.info( 'EnterpriseCourseEnrollment created: EnterpriseCustomer [%s] - User [%s] - CourseRun [%s]', enterprise_customer_uuid, user_id, course_run_id) else: LOGGER.warning( 'EnterpriseCourseEnrollment exists: EnterpriseCustomer [%s] - User [%s] - CourseRun [%s]', enterprise_customer_uuid, user_id, course_run_id) else: LOGGER.info( 'User [%s] is not linked with EnterpriseCustomer - [%s]', user_id, enterprise_customer.uuid, ) LOGGER.info('Created %s missing EnterpriseCourseEnrollments.', records_created) LOGGER.info('Exception raised for %s records.', records_failed)
def enroll_users_in_course( cls, enterprise_customer, course_id, course_mode, emails, enrollment_requester=None, enrollment_reason=None, discount=0.0, sales_force_id=None, ): """ Enroll existing users in a course, and create a pending enrollment for nonexisting users. Args: enterprise_customer: The EnterpriseCustomer which is sponsoring the enrollment course_id (str): The unique identifier of the course in which we're enrolling course_mode (str): The mode with which we're enrolling in the course emails: An iterable of email addresses which need to be enrolled enrollment_requester (User): Admin user who is requesting the enrollment. enrollment_reason (str): A reason for enrollment. discount (Decimal): Percentage discount for enrollment. sales_force_id (str): Salesforce opportunity id. Returns: successes: A list of users who were successfully enrolled in the course pending: A list of PendingEnterpriseCustomerUsers who were successfully linked and had pending enrollments created for them in the database failures: A list of users who could not be enrolled in the course """ existing_users, unregistered_emails = cls.get_users_by_email(emails) successes = [] pending = [] failures = [] for user in existing_users: succeeded = cls.enroll_user(enterprise_customer, user, course_mode, course_id) if succeeded: successes.append(user) if enrollment_requester and enrollment_reason: create_manual_enrollment_audit( enrollment_requester, user.email, UNENROLLED_TO_ENROLLED, enrollment_reason, course_id, role=MANUAL_ENROLLMENT_ROLE, ) else: failures.append(user) for email in unregistered_emails: pending_user = enterprise_customer.enroll_user_pending_registration( email, course_mode, course_id, enrollment_source=EnterpriseEnrollmentSource.get_source( EnterpriseEnrollmentSource.MANUAL), discount=discount, sales_force_id=sales_force_id, ) pending.append(pending_user) if enrollment_requester and enrollment_reason: create_manual_enrollment_audit( enrollment_requester, email, UNENROLLED_TO_ALLOWEDTOENROLL, enrollment_reason, course_id, role=MANUAL_ENROLLMENT_ROLE, ) return successes, pending, failures
def enroll_users_in_program( cls, enterprise_customer, program_details, course_mode, emails, cohort=None, enrollment_requester=None, enrollment_reason=None ): """ Enroll existing users in all courses in a program, and create pending enrollments for nonexisting users. Args: enterprise_customer: The EnterpriseCustomer which is sponsoring the enrollment program_details: The details of the program in which we're enrolling course_mode (str): The mode with which we're enrolling in the program emails: An iterable of email addresses which need to be enrolled Returns: successes: A list of users who were successfully enrolled in all courses of the program pending: A list of PendingEnterpriseCustomerUsers who were successfully linked and had pending enrollments created for them in the database failures: A list of users who could not be enrolled in the program """ existing_users, unregistered_emails = cls.get_users_by_email(emails) course_ids = get_course_runs_from_program(program_details) successes = [] pending = [] failures = [] for user in existing_users: succeeded = cls.enroll_user(enterprise_customer, user, course_mode, *course_ids) if succeeded: successes.append(user) if enrollment_requester and enrollment_reason: for course_id in course_ids: create_manual_enrollment_audit( enrollment_requester, user.email, UNENROLLED_TO_ENROLLED, enrollment_reason, course_id, role=MANUAL_ENROLLMENT_ROLE, ) else: failures.append(user) for email in unregistered_emails: pending_user = enterprise_customer.enroll_user_pending_registration( email, course_mode, *course_ids, cohort=cohort, enrollment_source=EnterpriseEnrollmentSource.get_source(EnterpriseEnrollmentSource.MANUAL) ) pending.append(pending_user) if enrollment_requester and enrollment_reason: for course_id in course_ids: create_manual_enrollment_audit( enrollment_requester, email, UNENROLLED_TO_ALLOWEDTOENROLL, enrollment_reason, course_id, role=MANUAL_ENROLLMENT_ROLE, ) return successes, pending, failures