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
c2191b87
Commit
c2191b87
authored
Apr 23, 2015
by
Clinton Blackburn
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added Acceptance Tests for Payment Flow
parent
22b83fb0
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
209 additions
and
86 deletions
+209
-86
.gitignore
+2
-0
acceptance_tests/api.py
+1
-27
acceptance_tests/config.py
+4
-1
acceptance_tests/mixins.py
+62
-3
acceptance_tests/pages.py
+69
-3
acceptance_tests/test_login_enrollment.py
+7
-41
acceptance_tests/test_payment.py
+49
-0
ecommerce/extensions/fulfillment/modules.py
+1
-3
ecommerce/settings/local.py
+11
-8
requirements/base.txt
+2
-0
requirements/test.txt
+1
-0
No files found.
.gitignore
View file @
c2191b87
...
@@ -51,6 +51,8 @@ diff_*.html
...
@@ -51,6 +51,8 @@ diff_*.html
report
report
edx_ecommerce.log
edx_ecommerce.log
venv
venv
acceptance_tests.*.log
acceptance_tests.*.png
# Override config files
# Override config files
override.cfg
override.cfg
...
...
acceptance_tests/api.py
View file @
c2191b87
import
datetime
import
requests
import
requests
from
requests.auth
import
AuthBase
from
requests.auth
import
AuthBase
from
acceptance_tests.config
import
(
ENROLLMENT_API_URL
,
ENROLLMENT_API_TOKEN
,
ECOMMERCE_API_SERVER_URL
,
from
acceptance_tests.config
import
ENROLLMENT_API_URL
,
ENROLLMENT_API_TOKEN
ECOMMERCE_API_TOKEN
)
class
BearerAuth
(
AuthBase
):
class
BearerAuth
(
AuthBase
):
...
@@ -31,26 +28,3 @@ class EnrollmentApiClient(object):
...
@@ -31,26 +28,3 @@ class EnrollmentApiClient(object):
"""
"""
url
=
'{host}/enrollment/{username},{course_id}'
.
format
(
host
=
self
.
host
,
username
=
username
,
course_id
=
course_id
)
url
=
'{host}/enrollment/{username},{course_id}'
.
format
(
host
=
self
.
host
,
username
=
username
,
course_id
=
course_id
)
return
requests
.
get
(
url
,
auth
=
BearerAuth
(
self
.
key
))
.
json
()
return
requests
.
get
(
url
,
auth
=
BearerAuth
(
self
.
key
))
.
json
()
class
EcommerceApiClient
(
object
):
def
__init__
(
self
,
host
=
None
,
key
=
None
):
self
.
host
=
host
or
'{}/api/v1'
.
format
(
ECOMMERCE_API_SERVER_URL
)
self
.
key
=
key
or
ECOMMERCE_API_TOKEN
def
orders
(
self
):
""" Retrieve the orders for the user linked to the authenticated user. """
url
=
'{}/orders/'
.
format
(
self
.
host
)
response
=
requests
.
get
(
url
,
auth
=
BearerAuth
(
self
.
key
))
data
=
response
.
json
()
status_code
=
response
.
status_code
if
status_code
!=
200
:
raise
Exception
(
'Invalid E-Commerce API response: [{}] - [{}]'
.
format
(
status_code
,
data
))
orders
=
data
[
'results'
]
for
order
in
orders
:
order
[
'date_placed'
]
=
datetime
.
datetime
.
strptime
(
order
[
'date_placed'
],
"
%
Y-
%
m-
%
dT
%
H:
%
M:
%
S.
%
fZ"
)
return
orders
acceptance_tests/config.py
View file @
c2191b87
...
@@ -10,7 +10,8 @@ ACCESS_TOKEN = os.environ.get('ACCESS_TOKEN', 'edx')
...
@@ -10,7 +10,8 @@ ACCESS_TOKEN = os.environ.get('ACCESS_TOKEN', 'edx')
# Application configuration
# Application configuration
APP_SERVER_URL
=
os
.
environ
.
get
(
'APP_SERVER_URL'
,
'http://localhost:8002'
)
.
strip
(
'/'
)
APP_SERVER_URL
=
os
.
environ
.
get
(
'APP_SERVER_URL'
,
'http://localhost:8002'
)
.
strip
(
'/'
)
ECOMMERCE_API_SERVER_URL
=
os
.
environ
.
get
(
'ECOMMERCE_API_SERVER_URL'
,
APP_SERVER_URL
)
.
strip
(
'/'
)
ECOMMERCE_API_SERVER_URL
=
os
.
environ
.
get
(
'ECOMMERCE_API_SERVER_URL'
,
APP_SERVER_URL
+
'/api/v2'
)
.
strip
(
'/'
)
ECOMMERCE_API_SIGNING_KEY
=
os
.
environ
.
get
(
'ECOMMERCE_API_SIGNING_KEY'
,
'edx'
)
ECOMMERCE_API_TOKEN
=
os
.
environ
.
get
(
'ECOMMERCE_API_AUTH_TOKEN'
,
ACCESS_TOKEN
)
ECOMMERCE_API_TOKEN
=
os
.
environ
.
get
(
'ECOMMERCE_API_AUTH_TOKEN'
,
ACCESS_TOKEN
)
# Amount of time allotted for processing an order. This value is used to match newly-placed orders in testing, and
# Amount of time allotted for processing an order. This value is used to match newly-placed orders in testing, and
...
@@ -21,6 +22,7 @@ ORDER_PROCESSING_TIME = int(os.environ.get('ORDER_PROCESSING_TIME', 15))
...
@@ -21,6 +22,7 @@ ORDER_PROCESSING_TIME = int(os.environ.get('ORDER_PROCESSING_TIME', 15))
ENABLE_AUTO_AUTH
=
str2bool
(
os
.
environ
.
get
(
'ENABLE_AUTO_AUTH'
,
False
))
ENABLE_AUTO_AUTH
=
str2bool
(
os
.
environ
.
get
(
'ENABLE_AUTO_AUTH'
,
False
))
ENABLE_OAUTH_TESTS
=
str2bool
(
os
.
environ
.
get
(
'ENABLE_OAUTH_TESTS'
,
True
))
ENABLE_OAUTH_TESTS
=
str2bool
(
os
.
environ
.
get
(
'ENABLE_OAUTH_TESTS'
,
True
))
COURSE_ID
=
os
.
environ
.
get
(
'COURSE_ID'
,
'edX/DemoX/Demo_Course'
)
COURSE_ID
=
os
.
environ
.
get
(
'COURSE_ID'
,
'edX/DemoX/Demo_Course'
)
VERIFIED_COURSE_ID
=
os
.
environ
.
get
(
'VERIFIED_COURSE_ID'
,
'edX/victor101/Victor_s_test_course'
)
# LMS configuration
# LMS configuration
BASIC_AUTH_USERNAME
=
os
.
environ
.
get
(
'BASIC_AUTH_USERNAME'
)
BASIC_AUTH_USERNAME
=
os
.
environ
.
get
(
'BASIC_AUTH_USERNAME'
)
...
@@ -29,6 +31,7 @@ LMS_URL = os.environ.get('LMS_URL').strip('/')
...
@@ -29,6 +31,7 @@ LMS_URL = os.environ.get('LMS_URL').strip('/')
LMS_USERNAME
=
os
.
environ
.
get
(
'LMS_USERNAME'
)
LMS_USERNAME
=
os
.
environ
.
get
(
'LMS_USERNAME'
)
LMS_EMAIL
=
os
.
environ
.
get
(
'LMS_EMAIL'
)
LMS_EMAIL
=
os
.
environ
.
get
(
'LMS_EMAIL'
)
LMS_PASSWORD
=
os
.
environ
.
get
(
'LMS_PASSWORD'
)
LMS_PASSWORD
=
os
.
environ
.
get
(
'LMS_PASSWORD'
)
HTTPS_RECEIPT_PAGE
=
str2bool
(
os
.
environ
.
get
(
'HTTPS_RECEIPT_PAGE'
,
True
))
if
ENABLE_OAUTH_TESTS
and
not
(
LMS_URL
and
LMS_USERNAME
and
LMS_PASSWORD
):
if
ENABLE_OAUTH_TESTS
and
not
(
LMS_URL
and
LMS_USERNAME
and
LMS_PASSWORD
):
raise
Exception
(
'LMS settings must be set in order to test OAuth.'
)
raise
Exception
(
'LMS settings must be set in order to test OAuth.'
)
...
...
acceptance_tests/mixins.py
View file @
c2191b87
from
acceptance_tests.config
import
ENABLE_AUTO_AUTH
,
APP_SERVER_URL
,
LMS_PASSWORD
,
LMS_EMAIL
import
logging
import
uuid
import
requests
from
acceptance_tests.api
import
EnrollmentApiClient
from
acceptance_tests.config
import
(
ENABLE_AUTO_AUTH
,
APP_SERVER_URL
,
LMS_PASSWORD
,
LMS_EMAIL
,
LMS_URL
,
BASIC_AUTH_USERNAME
,
BASIC_AUTH_PASSWORD
,
ECOMMERCE_API_SERVER_URL
,
ECOMMERCE_API_SIGNING_KEY
)
from
acceptance_tests.pages
import
LMSLoginPage
from
acceptance_tests.pages
import
LMSLoginPage
from
ecommerce_api_client.client
import
EcommerceApiClient
log
=
logging
.
getLogger
(
__name__
)
class
LoginMixin
(
object
):
class
LoginMixin
(
object
):
...
@@ -17,15 +29,62 @@ class LoginMixin(object):
...
@@ -17,15 +29,62 @@ class LoginMixin(object):
url
=
'{}/test/auto_auth/'
.
format
(
APP_SERVER_URL
)
url
=
'{}/test/auto_auth/'
.
format
(
APP_SERVER_URL
)
self
.
browser
.
get
(
url
)
self
.
browser
.
get
(
url
)
def
login_with_lms
(
self
,
course_id
=
None
):
def
login_with_lms
(
self
,
email
=
None
,
password
=
None
,
course_id
=
None
):
""" Visit LMS and login. """
""" Visit LMS and login. """
email
=
email
or
LMS_EMAIL
password
=
password
or
LMS_PASSWORD
# Note: We use Selenium directly here (as opposed to Bok Choy) to avoid issues with promises being broken.
# Note: We use Selenium directly here (as opposed to Bok Choy) to avoid issues with promises being broken.
self
.
lms_login_page
.
browser
.
get
(
self
.
lms_login_page
.
url
(
course_id
))
# pylint: disable=not-callable
self
.
lms_login_page
.
browser
.
get
(
self
.
lms_login_page
.
url
(
course_id
))
# pylint: disable=not-callable
self
.
lms_login_page
.
login
(
LMS_EMAIL
,
LMS_PASSWORD
)
self
.
lms_login_page
.
login
(
email
,
password
)
class
LogoutMixin
(
object
):
class
LogoutMixin
(
object
):
def
logout
(
self
):
def
logout
(
self
):
url
=
'{}/accounts/logout/'
.
format
(
APP_SERVER_URL
)
url
=
'{}/accounts/logout/'
.
format
(
APP_SERVER_URL
)
self
.
browser
.
get
(
url
)
self
.
browser
.
get
(
url
)
class
LmsUserMixin
(
object
):
password
=
'edx'
def
create_lms_user
(
self
,
username
=
None
,
password
=
None
,
email
=
None
):
username
=
username
or
(
'auto_auth_'
+
uuid
.
uuid4
()
.
hex
[
0
:
20
])
password
=
password
or
'edx'
email
=
email
or
'{}@example.com'
.
format
(
username
)
url
=
'{host}/auto_auth?no_login=true&username={username}&password={password}&email={email}'
.
format
(
host
=
LMS_URL
,
username
=
username
,
password
=
password
,
email
=
email
)
auth
=
None
if
BASIC_AUTH_USERNAME
and
BASIC_AUTH_PASSWORD
:
auth
=
(
BASIC_AUTH_USERNAME
,
BASIC_AUTH_PASSWORD
)
requests
.
get
(
url
,
auth
=
auth
)
return
username
,
password
,
email
class
EnrollmentApiMixin
(
object
):
def
setUp
(
self
):
super
(
EnrollmentApiMixin
,
self
)
.
setUp
()
self
.
enrollment_api_client
=
EnrollmentApiClient
()
def
assert_user_enrolled
(
self
,
username
,
course_id
,
mode
=
'honor'
):
status
=
self
.
enrollment_api_client
.
get_enrollment_status
(
username
,
course_id
)
self
.
assertDictContainsSubset
({
'is_active'
:
True
,
'mode'
:
mode
},
status
)
class
EcommerceApiMixin
(
object
):
@property
def
ecommerce_api_client
(
self
):
return
EcommerceApiClient
(
ECOMMERCE_API_SERVER_URL
,
ECOMMERCE_API_SIGNING_KEY
,
self
.
username
,
self
.
email
)
def
assert_order_created_and_completed
(
self
):
orders
=
self
.
ecommerce_api_client
.
get_orders
()
self
.
assertGreater
(
len
(
orders
),
0
,
'No orders found for the user!'
)
# TODO Validate this is the correct order.
order
=
orders
[
0
]
self
.
assertEqual
(
order
[
'status'
],
'Complete'
)
acceptance_tests/pages.py
View file @
c2191b87
import
abc
import
urllib
import
urllib
from
bok_choy.page_object
import
PageObject
from
bok_choy.page_object
import
PageObject
from
bok_choy.promise
import
EmptyPromise
from
bok_choy.promise
import
EmptyPromise
from
selenium.webdriver.support.select
import
Select
from
acceptance_tests.config
import
BASIC_AUTH_USERNAME
,
BASIC_AUTH_PASSWORD
,
APP_SERVER_URL
,
LMS_URL
from
acceptance_tests.config
import
BASIC_AUTH_USERNAME
,
BASIC_AUTH_PASSWORD
,
APP_SERVER_URL
,
LMS_URL
...
@@ -27,14 +29,22 @@ class DashboardHomePage(EcommerceAppPage):
...
@@ -27,14 +29,22 @@ class DashboardHomePage(EcommerceAppPage):
return
self
.
browser
.
title
.
startswith
(
'Dashboard | Oscar'
)
return
self
.
browser
.
title
.
startswith
(
'Dashboard | Oscar'
)
class
LMS
LoginPage
(
PageObject
):
class
LMS
Page
(
PageObject
):
# pylint: disable=abstract-method
def
url
(
self
,
course_id
=
None
):
# pylint: disable=arguments-differ
__metaclass__
=
abc
.
ABCMeta
url
=
'{0}/login'
.
format
(
LMS_URL
)
def
_build_url
(
self
,
path
):
url
=
'{0}/{1}'
.
format
(
LMS_URL
,
path
)
if
BASIC_AUTH_USERNAME
and
BASIC_AUTH_PASSWORD
:
if
BASIC_AUTH_USERNAME
and
BASIC_AUTH_PASSWORD
:
url
=
url
.
replace
(
'://'
,
'://{0}:{1}@'
.
format
(
BASIC_AUTH_USERNAME
,
BASIC_AUTH_PASSWORD
))
url
=
url
.
replace
(
'://'
,
'://{0}:{1}@'
.
format
(
BASIC_AUTH_USERNAME
,
BASIC_AUTH_PASSWORD
))
return
url
class
LMSLoginPage
(
LMSPage
):
def
url
(
self
,
course_id
=
None
):
# pylint: disable=arguments-differ
url
=
self
.
_build_url
(
'login'
)
if
course_id
:
if
course_id
:
params
=
{
'enrollment_action'
:
'enroll'
,
'course_id'
:
course_id
}
params
=
{
'enrollment_action'
:
'enroll'
,
'course_id'
:
course_id
}
url
=
'{0}?{1}'
.
format
(
url
,
urllib
.
urlencode
(
params
))
url
=
'{0}?{1}'
.
format
(
url
,
urllib
.
urlencode
(
params
))
...
@@ -54,3 +64,59 @@ class LMSLoginPage(PageObject):
...
@@ -54,3 +64,59 @@ class LMSLoginPage(PageObject):
# Wait for LMS to redirect to the dashboard
# Wait for LMS to redirect to the dashboard
EmptyPromise
(
self
.
_is_browser_on_lms_dashboard
(),
"LMS login redirected to dashboard"
)
.
fulfill
()
EmptyPromise
(
self
.
_is_browser_on_lms_dashboard
(),
"LMS login redirected to dashboard"
)
.
fulfill
()
class
LMSCourseModePage
(
LMSPage
):
def
is_browser_on_page
(
self
):
return
self
.
browser
.
title
.
lower
()
.
startswith
(
'enroll in'
)
@property
def
url
(
self
):
path
=
'course_modes/choose/{}/'
.
format
(
urllib
.
quote_plus
(
self
.
course_id
))
return
self
.
_build_url
(
path
)
def
__init__
(
self
,
browser
,
course_id
):
super
(
LMSCourseModePage
,
self
)
.
__init__
(
browser
)
self
.
course_id
=
course_id
def
purchase_verified
(
self
):
# Click the purchase button on the track selection page
self
.
q
(
css
=
'input[name=verified_mode]'
)
.
click
()
# Click the payment button
self
.
q
(
css
=
'a#cybersource'
)
.
click
()
# Wait for form to load
self
.
wait_for_element_presence
(
'#billing_details'
,
'Waiting for billing form to load.'
)
# Select the credit card type (Visa) first since it triggers the display of additional fields
self
.
q
(
css
=
'#card_type_001'
)
.
click
()
# Visa
# Select the appropriate <option> elements
select_fields
=
(
(
'#bill_to_address_country'
,
'US'
),
(
'#bill_to_address_state_us_ca'
,
'MA'
),
(
'#card_expiry_year'
,
'2020'
)
)
for
selector
,
value
in
select_fields
:
select
=
Select
(
self
.
browser
.
find_element_by_css_selector
(
selector
))
select
.
select_by_value
(
value
)
# Fill in the text fields
billing_information
=
{
'bill_to_forename'
:
'Ed'
,
'bill_to_surname'
:
'Xavier'
,
'bill_to_address_line1'
:
'141 Portland Ave.'
,
'bill_to_address_line2'
:
'9th Floor'
,
'bill_to_address_city'
:
'Cambridge'
,
'bill_to_address_postal_code'
:
'02141'
,
'bill_to_email'
:
'edx@example.com'
,
'card_number'
:
'4111111111111111'
,
'card_cvn'
:
'1234'
}
for
field
,
value
in
billing_information
.
items
():
self
.
q
(
css
=
'#'
+
field
)
.
fill
(
value
)
# Click the payment button
self
.
q
(
css
=
'input[type=submit]'
)
.
click
()
acceptance_tests/test_login_enrollment.py
View file @
c2191b87
import
datetime
import
logging
from
bok_choy.web_app_test
import
WebAppTest
from
bok_choy.web_app_test
import
WebAppTest
from
acceptance_tests.api
import
EnrollmentApiClient
,
EcommerceApiClient
from
acceptance_tests.config
import
COURSE_ID
from
acceptance_tests.config
import
COURSE_ID
,
LMS_USERNAME
,
ORDER_PROCESSING_TIME
from
acceptance_tests.mixins
import
LoginMixin
,
EcommerceApiMixin
,
EnrollmentApiMixin
,
LmsUserMixin
from
acceptance_tests.mixins
import
LoginMixin
log
=
logging
.
getLogger
(
__name__
)
class
LoginEnrollmentTests
(
LoginMixin
,
WebAppTest
):
class
LoginEnrollmentTests
(
EcommerceApiMixin
,
EnrollmentApiMixin
,
LmsUserMixin
,
LoginMixin
,
WebAppTest
):
def
setUp
(
self
):
def
setUp
(
self
):
super
(
LoginEnrollmentTests
,
self
)
.
setUp
()
super
(
LoginEnrollmentTests
,
self
)
.
setUp
()
self
.
course_id
=
COURSE_ID
self
.
course_id
=
COURSE_ID
self
.
username
=
LMS_USERNAME
self
.
username
,
self
.
password
,
self
.
email
=
self
.
create_lms_user
()
self
.
enrollment_api_client
=
EnrollmentApiClient
()
self
.
ecommerce_api_client
=
EcommerceApiClient
()
# TODO Delete existing enrollments
def
_test_honor_enrollment_common
(
self
):
"""
Validates an order is created for the logged in user and that a corresponding order has been created.
"""
# Get the latest order
orders
=
self
.
ecommerce_api_client
.
orders
()
self
.
assertGreater
(
len
(
orders
),
0
,
'No orders found for the user!'
)
order
=
orders
[
0
]
# TODO Find a better way to verify this is the correct enrollment.
# Verify the date and status
self
.
assertEqual
(
order
[
'status'
],
'Complete'
)
order_date
=
order
[
'date_placed'
]
now
=
datetime
.
datetime
.
utcnow
()
self
.
assertLess
(
order_date
,
now
)
self
.
assertGreater
(
order_date
,
now
-
datetime
.
timedelta
(
seconds
=
ORDER_PROCESSING_TIME
))
# Verify user enrolled in course
status
=
self
.
enrollment_api_client
.
get_enrollment_status
(
self
.
username
,
self
.
course_id
)
log
.
debug
(
status
)
self
.
assertDictContainsSubset
({
'is_active'
:
True
,
'mode'
:
'honor'
},
status
)
def
test_honor_enrollment_and_login
(
self
):
def
test_honor_enrollment_and_login
(
self
):
""" Verifies that a user can login and enroll in a course via the login page. """
""" Verifies that a user can login and enroll in a course via the login page. """
# Login and enroll via LMS
# Login and enroll via LMS
self
.
login_with_lms
(
self
.
course_id
)
self
.
login_with_lms
(
self
.
email
,
self
.
password
,
self
.
course_id
)
self
.
assert_order_created_and_completed
()
self
.
_test_honor_enrollment_common
(
)
self
.
assert_user_enrolled
(
self
.
username
,
self
.
course_id
)
acceptance_tests/test_payment.py
0 → 100644
View file @
c2191b87
from
bok_choy.web_app_test
import
WebAppTest
from
selenium.webdriver.common.by
import
By
from
selenium.webdriver.support.ui
import
WebDriverWait
from
selenium.webdriver.support
import
expected_conditions
as
EC
from
acceptance_tests.config
import
VERIFIED_COURSE_ID
,
HTTPS_RECEIPT_PAGE
from
acceptance_tests.mixins
import
LoginMixin
,
EnrollmentApiMixin
,
EcommerceApiMixin
,
LmsUserMixin
from
acceptance_tests.pages
import
LMSCourseModePage
class
VerifiedCertificatePaymentTests
(
EcommerceApiMixin
,
EnrollmentApiMixin
,
LmsUserMixin
,
LoginMixin
,
WebAppTest
):
def
setUp
(
self
):
super
(
VerifiedCertificatePaymentTests
,
self
)
.
setUp
()
self
.
course_id
=
VERIFIED_COURSE_ID
self
.
username
,
self
.
password
,
self
.
email
=
self
.
create_lms_user
()
def
test_payment
(
self
):
self
.
login_with_lms
(
self
.
email
,
self
.
password
)
course_modes_page
=
LMSCourseModePage
(
self
.
browser
,
self
.
course_id
)
course_modes_page
.
visit
()
course_modes_page
.
purchase_verified
()
if
not
HTTPS_RECEIPT_PAGE
:
self
.
browser
.
switch_to_alert
()
.
accept
()
# Wait for the payment processor response to be processed, and the receipt page updated.
WebDriverWait
(
self
.
browser
,
30
)
.
until
(
EC
.
presence_of_element_located
((
By
.
CLASS_NAME
,
'content-main'
)))
self
.
assert_order_created_and_completed
()
self
.
assert_user_enrolled
(
self
.
username
,
self
.
course_id
,
'verified'
)
# Verify we reach the receipt page.
self
.
assertIn
(
'receipt'
,
self
.
browser
.
title
.
lower
())
cells
=
self
.
browser
.
find_elements_by_css_selector
(
'table.report-receipt tbody td'
)
self
.
assertGreater
(
len
(
cells
),
0
)
order
=
self
.
ecommerce_api_client
.
get_orders
()[
0
]
line
=
order
[
'lines'
][
0
]
expected
=
[
order
[
'number'
],
line
[
'description'
],
order
[
'date_placed'
]
.
strftime
(
'
%
Y-
%
m-
%
dT
%
H:
%
M:
%
S'
),
'{amount} ({currency})'
.
format
(
amount
=
line
[
'line_price_excl_tax'
],
currency
=
order
[
'currency'
])
]
actual
=
[
cell
.
text
for
cell
in
cells
]
self
.
assertListEqual
(
actual
,
expected
)
ecommerce/extensions/fulfillment/modules.py
View file @
c2191b87
...
@@ -90,8 +90,6 @@ class EnrollmentFulfillmentModule(BaseFulfillmentModule):
...
@@ -90,8 +90,6 @@ class EnrollmentFulfillmentModule(BaseFulfillmentModule):
"""
"""
REQUEST_TIMEOUT
=
5
def
get_supported_lines
(
self
,
order
,
lines
):
def
get_supported_lines
(
self
,
order
,
lines
):
""" Return a list of lines that can be fulfilled through enrollment.
""" Return a list of lines that can be fulfilled through enrollment.
...
@@ -168,7 +166,7 @@ class EnrollmentFulfillmentModule(BaseFulfillmentModule):
...
@@ -168,7 +166,7 @@ class EnrollmentFulfillmentModule(BaseFulfillmentModule):
enrollment_api_url
,
enrollment_api_url
,
data
=
json
.
dumps
(
data
),
data
=
json
.
dumps
(
data
),
headers
=
headers
,
headers
=
headers
,
timeout
=
self
.
REQUEST_TIMEOUT
timeout
=
getattr
(
settings
,
'ENROLLMENT_FULFILLMENT_TIMEOUT'
,
5
)
)
)
if
response
.
status_code
==
status
.
HTTP_200_OK
:
if
response
.
status_code
==
status
.
HTTP_200_OK
:
...
...
ecommerce/settings/local.py
View file @
c2191b87
...
@@ -71,13 +71,17 @@ INTERNAL_IPS = ('127.0.0.1',)
...
@@ -71,13 +71,17 @@ INTERNAL_IPS = ('127.0.0.1',)
# Do not include a trailing slash.
# Do not include a trailing slash.
LMS_URL_ROOT
=
'http://127.0.0.1:8000'
LMS_URL_ROOT
=
'http://127.0.0.1:8000'
def
get_lms_url
(
path
):
return
LMS_URL_ROOT
+
path
# The location of the LMS heartbeat page
# The location of the LMS heartbeat page
LMS_HEARTBEAT_URL
=
LMS_URL_ROOT
+
'/heartbeat'
LMS_HEARTBEAT_URL
=
get_lms_url
(
'/heartbeat'
)
# The location of the LMS student dashboard
# The location of the LMS student dashboard
LMS_DASHBOARD_URL
=
LMS_URL_ROOT
+
'/dashboard'
LMS_DASHBOARD_URL
=
get_lms_url
(
'/dashboard'
)
OAUTH2_PROVIDER_URL
=
LMS_URL_ROOT
+
'/oauth2'
OAUTH2_PROVIDER_URL
=
get_lms_url
(
'/oauth2'
)
# END URL CONFIGURATION
# END URL CONFIGURATION
...
@@ -93,7 +97,8 @@ JWT_AUTH['JWT_SECRET_KEY'] = 'insecure-secret-key'
...
@@ -93,7 +97,8 @@ JWT_AUTH['JWT_SECRET_KEY'] = 'insecure-secret-key'
# ORDER PROCESSING
# ORDER PROCESSING
ENROLLMENT_API_URL
=
LMS_URL_ROOT
+
'/api/enrollment/v1/enrollment'
ENROLLMENT_API_URL
=
get_lms_url
(
'/api/enrollment/v1/enrollment'
)
ENROLLMENT_FULFILLMENT_TIMEOUT
=
15
# devstack is slow!
EDX_API_KEY
=
'replace-me'
EDX_API_KEY
=
'replace-me'
# END ORDER PROCESSING
# END ORDER PROCESSING
...
@@ -106,10 +111,8 @@ PAYMENT_PROCESSOR_CONFIG = {
...
@@ -106,10 +111,8 @@ PAYMENT_PROCESSOR_CONFIG = {
'access_key'
:
'fake-access-key'
,
'access_key'
:
'fake-access-key'
,
'secret_key'
:
'fake-secret-key'
,
'secret_key'
:
'fake-secret-key'
,
'payment_page_url'
:
'https://replace-me/'
,
'payment_page_url'
:
'https://replace-me/'
,
# TODO: XCOM-202 must be completed before any other receipt page is used.
'receipt_page_url'
:
get_lms_url
(
'/commerce/checkout/receipt/'
),
# By design this specific receipt page is expected.
'cancel_page_url'
:
get_lms_url
(
'/commerce/checkout/cancel/'
)
'receipt_page_url'
:
'https://replace-me/verify_student/payment-confirmation/'
,
'cancel_page_url'
:
'https://replace-me/'
,
}
}
}
}
# END PAYMENT PROCESSING
# END PAYMENT PROCESSING
...
...
requirements/base.txt
View file @
c2191b87
...
@@ -14,3 +14,5 @@ jsonfield==1.0.3
...
@@ -14,3 +14,5 @@ jsonfield==1.0.3
logutils==0.3.3
logutils==0.3.3
pycountry==1.10
pycountry==1.10
requests==2.6.0
requests==2.6.0
git+https://github.com/edx/ecommerce-api-client.git@0.1.0#egg=ecommerce-api-client
requirements/test.txt
View file @
c2191b87
...
@@ -12,3 +12,4 @@ nose-ignore-docstring==0.2
...
@@ -12,3 +12,4 @@ nose-ignore-docstring==0.2
pep8==1.6.2
pep8==1.6.2
pylint==1.4.1
pylint==1.4.1
selenium==2.45.0
selenium==2.45.0
slumber==0.7.0
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