Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
ecommerce
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
ecommerce
Commits
57432017
Commit
57432017
authored
Feb 14, 2018
by
Saleem Latif
Committed by
Saleem Latif
Feb 27, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added management command to create enrollment codes for courses.
parent
93717b90
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
230 additions
and
0 deletions
+230
-0
ecommerce/courses/management/commands/create_enrollment_codes.py
+230
-0
ecommerce/courses/tests/test_create_enrollment_codes_command.py
+0
-0
No files found.
ecommerce/courses/management/commands/create_enrollment_codes.py
0 → 100644
View file @
57432017
"""
This command generates enrollment codes for courses.
"""
from
__future__
import
unicode_literals
import
logging
import
os
from
django.core.management
import
BaseCommand
,
CommandError
from
ecommerce.core.constants
import
ENROLLMENT_CODE_SEAT_TYPES
from
ecommerce.courses.models
import
Course
logger
=
logging
.
getLogger
(
__name__
)
class
CourseInfoError
(
Exception
):
"""
Raised when course does not have all the required data.
"""
pass
class
Command
(
BaseCommand
):
"""
Creates enrollment codes for courses.
"""
help
=
'Create enrollment codes for courses.'
def
add_arguments
(
self
,
parser
):
parser
.
add_argument
(
'--course-ids-file'
,
action
=
'store'
,
dest
=
'course_ids_file'
,
default
=
None
,
help
=
'Path of the file to read courses id from.'
,
type
=
str
,
)
parser
.
add_argument
(
'--batch-limit'
,
action
=
'store'
,
dest
=
'batch_limit'
,
default
=
100
,
help
=
'Number of courses in each batch of enrollment code creation.'
,
type
=
int
,
)
def
handle
(
self
,
*
args
,
**
options
):
course_ids_file
=
options
[
'course_ids_file'
]
batch_limit
=
options
[
'batch_limit'
]
if
course_ids_file
:
if
not
os
.
path
.
exists
(
course_ids_file
):
raise
CommandError
(
'Pass the correct absolute path to course ids file as --course_ids_file argument.'
)
total_courses
,
failed_courses
=
self
.
_generate_enrollment_codes_from_file
(
course_ids_file
)
else
:
total_courses
,
failed_courses
=
self
.
_generate_enrollment_codes_from_db
(
batch_limit
)
if
failed_courses
:
logger
.
error
(
'Completed enrollment codes generation.
%
d of
%
d failed.'
,
len
(
failed_courses
),
total_courses
)
logger
.
error
(
'
\n
'
.
join
([
'Failed courses:'
]
+
failed_courses
))
else
:
logger
.
info
(
'Successfully generated enrollment codes for the batch of
%
s courses.'
,
total_courses
)
def
_generate_enrollment_codes_from_db
(
self
,
batch_limit
):
"""
Generate enrollment codes for the course.
Arguments:
batch_limit (int): How many courses to fetch from db to process in each batch.
Returns:
(total_course, failed_course): a tuple containing count of course processed and a list containing ids of
courses whose enrollment codes could not be generated.
"""
failed_courses
=
[]
total_courses
=
0
courses
=
Course
.
objects
.
all
()[
0
:
batch_limit
]
while
len
(
courses
)
>
0
:
total_courses
+=
len
(
courses
)
logger
.
info
(
'Creating enrollment code for
%
d courses.'
,
courses
.
count
())
for
course
in
courses
:
try
:
self
.
_generate_enrollment_code
(
course
)
except
CourseInfoError
as
error
:
logger
.
error
(
'Enrollment code generation failed for "
%
s" course. Because
%
s'
,
course
.
id
,
error
.
message
,
)
failed_courses
.
append
(
course
.
id
)
courses
=
Course
.
objects
.
all
()[
total_courses
:
total_courses
+
batch_limit
]
return
total_courses
,
failed_courses
def
_generate_enrollment_codes_from_file
(
self
,
course_ids_file
):
"""
Generate enrollment codes for the course provided in the course ids file.
Arguments:
course_ids_file (str): path of the file containing course ids.
Returns:
(total_course, failed_course): a tuple containing count of course processed and a list containing ids of
courses whose enrollment codes could not be generated.
"""
failed_courses
=
[]
with
open
(
course_ids_file
,
'r'
)
as
file_handler
:
course_ids
=
file_handler
.
readlines
()
total_courses
=
len
(
course_ids
)
logger
.
info
(
'Creating enrollment code for
%
d courses.'
,
total_courses
)
for
index
,
course_id
in
enumerate
(
course_ids
,
start
=
1
):
try
:
course_id
=
course_id
.
strip
()
course
=
Course
.
objects
.
get
(
id
=
course_id
)
self
.
_generate_enrollment_code
(
course
)
except
Course
.
DoesNotExist
:
failed_courses
.
append
(
course_id
)
logger
.
error
(
'(
%
d/
%
d) Failed to generate enrollment codes for "
%
s": Course does not exist.'
,
index
,
total_courses
,
course_id
)
except
CourseInfoError
as
error
:
logger
.
error
(
'Enrollment code generation failed for "
%
s" course. Because
%
s'
,
course
.
id
,
error
.
message
,
)
failed_courses
.
append
(
course
.
id
)
return
total_courses
,
failed_courses
def
_generate_enrollment_code
(
self
,
course
):
"""
Generate enrollment code for the given course.
Enrollment code is generated if
1. The course has a course mode that supports enrollment codes AND
2. The course does not already have an enrollment code for that course mode.
Arguments:
course (Course): E-Commerce course object.
"""
if
self
.
is_course_eligible_for_enrollment_code
(
course
)
and
not
course
.
get_enrollment_code
():
seat_type
,
price
,
id_verification_required
=
self
.
get_course_info
(
course
)
course
.
_create_or_update_enrollment_code
(
# pylint: disable=protected-access
seat_type
=
seat_type
,
id_verification_required
=
id_verification_required
,
partner
=
course
.
partner
,
price
=
price
,
expires
=
None
)
logger
.
info
(
'Enrollment code generated for "
%
s" course.'
,
course
.
id
)
elif
self
.
is_course_eligible_for_enrollment_code
(
course
)
and
course
.
get_enrollment_code
():
logger
.
info
(
'Skipping enrollment code generation for "
%
s" course due to existing enrollment codes.'
,
course
.
id
,
)
else
:
logger
.
info
(
'Skipping enrollment code generation for "
%
s" course. '
'Because enrollment codes are not allowed for "
%
s" seat type.'
,
course
.
id
,
', '
.
join
([
getattr
(
seat
.
attr
,
'certificate_type'
,
''
)
.
lower
()
for
seat
in
course
.
seat_products
]),
)
@staticmethod
def
is_course_eligible_for_enrollment_code
(
course
):
"""
Determine if given course is eligible for an enrollment code.
Courses that have one of the following seat types are eligible for an enrollment code.
1. verified
2. professional
3. no-id-professional
Arguments:
course (Course): E-Commerce course object.
Returns:
(bool): True if given course is eligible for enrollment code, False otherwise.
"""
seat_types
=
[
getattr
(
seat
.
attr
,
'certificate_type'
,
''
)
.
lower
()
for
seat
in
course
.
seat_products
]
for
seat_type
in
seat_types
:
if
seat_type
in
ENROLLMENT_CODE_SEAT_TYPES
:
return
True
return
False
@staticmethod
def
get_course_info
(
course
):
"""
Get course info required for the creation of enrollment code.
Arguments:
course (Course): E-Commerce course object.
Returns:
(seat_type, price, id_verification_required): A tuple containing the following info
seat_type: Course seat type e.g. verified, professional or no-id-professional
price: Price of the course.
id_verification_required: boolean indicating whether course requires student identity verification.
Raises:
(Exception): Raised if given course has either multiple seats eligible for enrollment code or no seat
eligible for enrollment code.
"""
seats
=
[
seat
for
seat
in
course
.
seat_products
if
getattr
(
seat
.
attr
,
'certificate_type'
,
''
)
.
lower
()
in
ENROLLMENT_CODE_SEAT_TYPES
]
if
len
(
seats
)
==
1
:
seat
=
seats
[
0
]
seat_type
=
getattr
(
seat
.
attr
,
'certificate_type'
,
''
)
.
lower
()
price
=
seat
.
stockrecords
.
all
()[
0
]
.
price_excl_tax
id_verification_required
=
getattr
(
seat
.
attr
,
'id_verification_required'
,
False
)
return
seat_type
,
price
,
id_verification_required
elif
len
(
seats
)
>
1
:
raise
CourseInfoError
(
'Course "
%
s" has multiple seats eligible for enrollment codes.'
%
course
.
id
)
else
:
raise
CourseInfoError
(
'Course "
%
s" does not have any seat eligible for enrollment codes.'
%
course
.
id
)
ecommerce/courses/tests/test_create_enrollment_codes_command.py
0 → 100644
View file @
57432017
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment