Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
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
edx-platform
Commits
bb219ed4
Commit
bb219ed4
authored
Jun 12, 2017
by
rabia23
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into ri/EDUCATOR-394-disable-self-generation-certificates
parents
64845801
484ec256
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
283 additions
and
23 deletions
+283
-23
lms/djangoapps/courseware/views/views.py
+6
-1
openedx/core/djangoapps/catalog/tests/factories.py
+58
-4
openedx/core/djangoapps/programs/tests/test_utils.py
+155
-9
openedx/core/djangoapps/programs/utils.py
+64
-9
No files found.
lms/djangoapps/courseware/views/views.py
View file @
bb219ed4
...
...
@@ -801,8 +801,13 @@ def program_marketing(request, program_uuid):
if
not
program_data
:
raise
Http404
program
=
ProgramMarketingDataExtender
(
program_data
,
request
.
user
)
.
extend
()
skus
=
program
.
get
(
'skus'
)
ecommerce_service
=
EcommerceService
()
return
render_to_response
(
'courseware/program_marketing.html'
,
{
'program'
:
ProgramMarketingDataExtender
(
program_data
,
request
.
user
)
.
extend
()
'buy_button_href'
:
ecommerce_service
.
get_checkout_page_url
(
*
skus
)
if
skus
else
'#courses'
,
'program'
:
program
,
})
...
...
openedx/core/djangoapps/catalog/tests/factories.py
View file @
bb219ed4
...
...
@@ -3,6 +3,7 @@
from
functools
import
partial
import
factory
import
uuid
from
faker
import
Faker
...
...
@@ -34,6 +35,19 @@ def generate_zulu_datetime():
return
fake
.
date_time
()
.
isoformat
()
+
'Z'
def
generate_price_ranges
():
return
[{
'currency'
:
'USD'
,
'max'
:
1000
,
'min'
:
100
,
'total'
:
500
}]
def
generate_seat_sku
():
return
uuid
.
uuid4
()
.
hex
[:
7
]
.
upper
()
class
DictFactoryBase
(
factory
.
Factory
):
"""
Subclass this to make factories that can be used to produce fake API response
...
...
@@ -77,12 +91,15 @@ class OrganizationFactory(DictFactoryBase):
key
=
factory
.
Faker
(
'word'
)
name
=
factory
.
Faker
(
'company'
)
uuid
=
factory
.
Faker
(
'uuid4'
)
logo_image_url
=
factory
.
Faker
(
'image_url'
)
class
SeatFactory
(
DictFactoryBase
):
type
=
factory
.
Faker
(
'word'
)
price
=
factory
.
Faker
(
'random_int'
)
currency
=
'USD'
price
=
factory
.
Faker
(
'random_int'
)
sku
=
factory
.
LazyFunction
(
generate_seat_sku
)
type
=
'verified'
upgrade_deadline
=
factory
.
LazyFunction
(
generate_zulu_datetime
)
class
CourseRunFactory
(
DictFactoryBase
):
...
...
@@ -91,13 +108,13 @@ class CourseRunFactory(DictFactoryBase):
enrollment_end
=
factory
.
LazyFunction
(
generate_zulu_datetime
)
enrollment_start
=
factory
.
LazyFunction
(
generate_zulu_datetime
)
image
=
ImageFactory
()
is_enrolled
=
False
key
=
factory
.
LazyFunction
(
generate_course_run_key
)
marketing_url
=
factory
.
Faker
(
'url'
)
pacing_type
=
'self_paced'
seats
=
factory
.
LazyFunction
(
partial
(
generate_instances
,
SeatFactory
))
short_description
=
factory
.
Faker
(
'sentence'
)
start
=
factory
.
LazyFunction
(
generate_zulu_datetime
)
status
=
'published'
title
=
factory
.
Faker
(
'catch_phrase'
)
type
=
'verified'
uuid
=
factory
.
Faker
(
'uuid4'
)
...
...
@@ -112,20 +129,57 @@ class CourseFactory(DictFactoryBase):
uuid
=
factory
.
Faker
(
'uuid4'
)
class
JobOutlookItemFactory
(
DictFactoryBase
):
value
=
factory
.
Faker
(
'sentence'
)
class
PersonFactory
(
DictFactoryBase
):
bio
=
factory
.
Faker
(
'paragraphs'
)
given_name
=
factory
.
Faker
(
'first_name'
)
family_name
=
factory
.
Faker
(
'last_name'
)
profile_image_url
=
factory
.
Faker
(
'image_url'
)
uuid
=
factory
.
Faker
(
'uuid4'
)
class
EndorserFactory
(
DictFactoryBase
):
person
=
PersonFactory
()
quote
=
factory
.
Faker
(
'sentence'
)
class
ExpectedLearningItemFactory
(
DictFactoryBase
):
value
=
factory
.
Faker
(
'sentence'
)
class
FAQFactory
(
DictFactoryBase
):
answer
=
factory
.
Faker
(
'sentence'
)
question
=
factory
.
Faker
(
'sentence'
)
class
ProgramFactory
(
DictFactoryBase
):
authoring_organizations
=
factory
.
LazyFunction
(
partial
(
generate_instances
,
OrganizationFactory
,
count
=
1
))
applicable_seat_types
=
[]
banner_image
=
factory
.
LazyFunction
(
generate_sized_stdimage
)
card_image_url
=
factory
.
Faker
(
'image_url'
)
courses
=
factory
.
LazyFunction
(
partial
(
generate_instances
,
CourseFactory
))
expected_learning_items
=
factory
.
LazyFunction
(
partial
(
generate_instances
,
CourseFactory
))
faq
=
factory
.
LazyFunction
(
partial
(
generate_instances
,
FAQFactory
))
hidden
=
False
individual_endorsements
=
factory
.
LazyFunction
(
partial
(
generate_instances
,
EndorserFactory
))
is_program_eligible_for_one_click_purchase
=
True
job_outlook_items
=
factory
.
LazyFunction
(
partial
(
generate_instances
,
JobOutlookItemFactory
))
marketing_slug
=
factory
.
Faker
(
'slug'
)
marketing_url
=
factory
.
Faker
(
'url'
)
max_hours_effort_per_week
=
fake
.
random_int
(
21
,
28
)
min_hours_effort_per_week
=
fake
.
random_int
(
7
,
14
)
overview
=
factory
.
Faker
(
'sentence'
)
price_ranges
=
factory
.
LazyFunction
(
generate_price_ranges
)
staff
=
factory
.
LazyFunction
(
partial
(
generate_instances
,
PersonFactory
))
status
=
'active'
subtitle
=
factory
.
Faker
(
'sentence'
)
title
=
factory
.
Faker
(
'catch_phrase'
)
type
=
factory
.
Faker
(
'word'
)
uuid
=
factory
.
Faker
(
'uuid4'
)
hidden
=
False
weeks_to_complete
=
fake
.
random_int
(
1
,
45
)
class
ProgramTypeFactory
(
DictFactoryBase
):
...
...
openedx/core/djangoapps/programs/tests/test_utils.py
View file @
bb219ed4
This diff is collapsed.
Click to expand it.
openedx/core/djangoapps/programs/utils.py
View file @
bb219ed4
# -*- coding: utf-8 -*-
"""Helper functions for working with Programs."""
import
datetime
import
logging
from
collections
import
defaultdict
from
copy
import
deepcopy
from
itertools
import
chain
...
...
@@ -8,17 +9,21 @@ from urlparse import urljoin
from
dateutil.parser
import
parse
from
django.conf
import
settings
from
django.contrib.auth
import
get_user_model
from
django.core.cache
import
cache
from
django.core.urlresolvers
import
reverse
from
django.utils.functional
import
cached_property
from
edx_rest_api_client.exceptions
import
SlumberBaseException
from
opaque_keys.edx.keys
import
CourseKey
from
pytz
import
utc
from
requests.exceptions
import
ConnectionError
,
Timeout
from
course_modes.models
import
CourseMode
from
lms.djangoapps.certificates
import
api
as
certificate_api
from
lms.djangoapps.commerce.utils
import
EcommerceService
from
lms.djangoapps.courseware.access
import
has_access
from
openedx.core.djangoapps.catalog.utils
import
get_programs
from
openedx.core.djangoapps.commerce.utils
import
ecommerce_api_client
from
openedx.core.djangoapps.content.course_overviews.models
import
CourseOverview
from
openedx.core.djangoapps.credentials.utils
import
get_credentials
from
student.models
import
CourseEnrollment
...
...
@@ -28,6 +33,8 @@ from xmodule.modulestore.django import modulestore
# The datetime module's strftime() methods require a year >= 1900.
DEFAULT_ENROLLMENT_START_DATE
=
datetime
.
datetime
(
1900
,
1
,
1
,
tzinfo
=
utc
)
log
=
logging
.
getLogger
(
__name__
)
def
get_program_marketing_url
(
programs_config
):
"""Build a URL used to link to programs on the marketing site."""
...
...
@@ -507,27 +514,25 @@ class ProgramMarketingDataExtender(ProgramDataExtender):
uuid
=
self
.
data
[
'uuid'
]
)
program_instructors
=
cache
.
get
(
cache_key
)
is_learner_eligible_for_one_click_purchase
=
self
.
data
[
'is_program_eligible_for_one_click_purchase'
]
for
course
in
self
.
data
[
'courses'
]:
self
.
_execute
(
'_collect_course'
,
course
)
if
not
program_instructors
:
for
course_run
in
course
[
'course_runs'
]:
self
.
_execute
(
'_collect_instructors'
,
course_run
)
if
is_learner_eligible_for_one_click_purchase
:
is_learner_eligible_for_one_click_purchase
=
not
any
(
course_run
[
'is_enrolled'
]
for
course_run
in
course
[
'course_runs'
]
)
if
not
program_instructors
:
# We cache the program instructors list to avoid repeated modulestore queries
program_instructors
=
self
.
instructors
.
values
()
cache
.
set
(
cache_key
,
program_instructors
,
3600
)
self
.
data
.
update
({
'instructors'
:
program_instructors
,
'is_learner_eligible_for_one_click_purchase'
:
is_learner_eligible_for_one_click_purchase
,
})
self
.
data
[
'instructors'
]
=
program_instructors
def
extend
(
self
):
"""Execute extension handlers, returning the extended data."""
self
.
data
.
update
(
super
(
ProgramMarketingDataExtender
,
self
)
.
extend
())
self
.
_collect_one_click_purchase_eligibility_data
()
return
self
.
data
@classmethod
def
_handlers
(
cls
,
prefix
):
...
...
@@ -582,3 +587,53 @@ class ProgramMarketingDataExtender(ProgramDataExtender):
self
.
instructors
.
update
(
{
instructor
.
get
(
'name'
):
instructor
for
instructor
in
course_instructors
.
get
(
'instructors'
,
[])}
)
def
_collect_one_click_purchase_eligibility_data
(
self
):
"""
Extend the program data with data about learner's eligibility for one click purchase,
discount data of the program and SKUs of seats that should be added to basket.
"""
applicable_seat_types
=
self
.
data
[
'applicable_seat_types'
]
is_learner_eligible_for_one_click_purchase
=
self
.
data
[
'is_program_eligible_for_one_click_purchase'
]
skus
=
[]
if
is_learner_eligible_for_one_click_purchase
:
for
course
in
self
.
data
[
'courses'
]:
is_learner_eligible_for_one_click_purchase
=
not
any
(
course_run
[
'is_enrolled'
]
for
course_run
in
course
[
'course_runs'
]
)
if
is_learner_eligible_for_one_click_purchase
:
published_course_runs
=
filter
(
lambda
run
:
run
[
'status'
]
==
'published'
,
course
[
'course_runs'
])
if
len
(
published_course_runs
)
==
1
:
for
seat
in
published_course_runs
[
0
][
'seats'
]:
if
seat
[
'type'
]
in
applicable_seat_types
:
skus
.
append
(
seat
[
'sku'
])
else
:
# If a course in the program has more than 1 published course run
# learner won't be eligible for a one click purchase.
is_learner_eligible_for_one_click_purchase
=
False
skus
=
[]
break
else
:
skus
=
[]
break
if
skus
:
try
:
User
=
get_user_model
()
service_user
=
User
.
objects
.
get
(
username
=
settings
.
ECOMMERCE_SERVICE_WORKER_USERNAME
)
api
=
ecommerce_api_client
(
service_user
)
# Make an API call to calculate the discounted price
discount_data
=
api
.
baskets
.
calculate
.
get
(
sku
=
skus
)
self
.
data
.
update
({
'discount_data'
:
discount_data
,
'full_program_price'
:
discount_data
[
'total_incl_tax'
]
})
except
(
ConnectionError
,
SlumberBaseException
,
Timeout
):
log
.
exception
(
'Failed to get discount price for following product SKUs:
%
s '
,
', '
.
join
(
skus
))
self
.
data
.
update
({
'is_learner_eligible_for_one_click_purchase'
:
is_learner_eligible_for_one_click_purchase
,
'skus'
:
skus
,
})
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