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
c74cd970
Commit
c74cd970
authored
Aug 02, 2017
by
Waheed Ahmed
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added new signal to refund on un-enrollment from LMS dashboard.
LEARNER-1801
parent
3e7243ea
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
28 additions
and
29 deletions
+28
-29
common/djangoapps/student/models.py
+1
-0
common/djangoapps/student/tests/test_views.py
+14
-11
common/djangoapps/student/views.py
+3
-1
lms/djangoapps/commerce/signals.py
+4
-6
lms/djangoapps/commerce/tests/test_signals.py
+6
-11
No files found.
common/djangoapps/student/models.py
View file @
c74cd970
...
@@ -60,6 +60,7 @@ from util.query import use_read_replica_if_available
...
@@ -60,6 +60,7 @@ from util.query import use_read_replica_if_available
UNENROLL_DONE
=
Signal
(
providing_args
=
[
"course_enrollment"
,
"skip_refund"
])
UNENROLL_DONE
=
Signal
(
providing_args
=
[
"course_enrollment"
,
"skip_refund"
])
ENROLL_STATUS_CHANGE
=
Signal
(
providing_args
=
[
"event"
,
"user"
,
"course_id"
,
"mode"
,
"cost"
,
"currency"
])
ENROLL_STATUS_CHANGE
=
Signal
(
providing_args
=
[
"event"
,
"user"
,
"course_id"
,
"mode"
,
"cost"
,
"currency"
])
REFUND_ORDER
=
Signal
(
providing_args
=
[
"course_enrollment"
])
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
AUDIT_LOG
=
logging
.
getLogger
(
"audit"
)
AUDIT_LOG
=
logging
.
getLogger
(
"audit"
)
SessionStore
=
import_module
(
settings
.
SESSION_ENGINE
)
.
SessionStore
# pylint: disable=invalid-name
SessionStore
=
import_module
(
settings
.
SESSION_ENGINE
)
.
SessionStore
# pylint: disable=invalid-name
...
...
common/djangoapps/student/tests/test_views.py
View file @
c74cd970
...
@@ -18,7 +18,7 @@ from pyquery import PyQuery as pq
...
@@ -18,7 +18,7 @@ from pyquery import PyQuery as pq
from
student.cookies
import
get_user_info_cookie_data
from
student.cookies
import
get_user_info_cookie_data
from
student.helpers
import
DISABLE_UNENROLL_CERT_STATES
from
student.helpers
import
DISABLE_UNENROLL_CERT_STATES
from
student.models
import
CourseEnrollment
,
UserProfile
from
student.models
import
CourseEnrollment
,
REFUND_ORDER
,
UserProfile
from
student.tests.factories
import
CourseEnrollmentFactory
,
UserFactory
from
student.tests.factories
import
CourseEnrollmentFactory
,
UserFactory
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.modulestore.tests.django_utils
import
SharedModuleStoreTestCase
from
xmodule.modulestore.tests.django_utils
import
SharedModuleStoreTestCase
...
@@ -91,16 +91,19 @@ class TestStudentDashboardUnenrollments(SharedModuleStoreTestCase):
...
@@ -91,16 +91,19 @@ class TestStudentDashboardUnenrollments(SharedModuleStoreTestCase):
self
.
cert_status
=
cert_status
self
.
cert_status
=
cert_status
with
patch
(
'student.views.cert_info'
,
side_effect
=
self
.
mock_cert
):
with
patch
(
'student.views.cert_info'
,
side_effect
=
self
.
mock_cert
):
response
=
self
.
client
.
post
(
with
patch
(
'commerce.signals.handle_refund_order'
)
as
mock_refund_handler
:
reverse
(
'change_enrollment'
),
REFUND_ORDER
.
connect
(
mock_refund_handler
)
{
'enrollment_action'
:
'unenroll'
,
'course_id'
:
self
.
course
.
id
}
response
=
self
.
client
.
post
(
)
reverse
(
'change_enrollment'
),
{
'enrollment_action'
:
'unenroll'
,
'course_id'
:
self
.
course
.
id
}
self
.
assertEqual
(
response
.
status_code
,
status_code
)
)
if
status_code
==
200
:
course_enrollment
.
assert_called_with
(
self
.
user
,
self
.
course
.
id
)
self
.
assertEqual
(
response
.
status_code
,
status_code
)
else
:
if
status_code
==
200
:
course_enrollment
.
assert_not_called
()
course_enrollment
.
assert_called_with
(
self
.
user
,
self
.
course
.
id
)
self
.
assertTrue
(
mock_refund_handler
.
called
)
else
:
course_enrollment
.
assert_not_called
()
def
test_no_cert_status
(
self
):
def
test_no_cert_status
(
self
):
""" Assert that the dashboard loads when cert_status is None."""
""" Assert that the dashboard loads when cert_status is None."""
...
...
common/djangoapps/student/views.py
View file @
c74cd970
...
@@ -119,7 +119,8 @@ from student.models import (
...
@@ -119,7 +119,8 @@ from student.models import (
UserStanding
,
UserStanding
,
anonymous_id_for_user
,
anonymous_id_for_user
,
create_comments_service_user
,
create_comments_service_user
,
unique_id_for_user
unique_id_for_user
,
REFUND_ORDER
)
)
from
student.tasks
import
send_activation_email
from
student.tasks
import
send_activation_email
from
third_party_auth
import
pipeline
,
provider
from
third_party_auth
import
pipeline
,
provider
...
@@ -1267,6 +1268,7 @@ def change_enrollment(request, check_access=True):
...
@@ -1267,6 +1268,7 @@ def change_enrollment(request, check_access=True):
return
HttpResponseBadRequest
(
_
(
"Your certificate prevents you from unenrolling from this course"
))
return
HttpResponseBadRequest
(
_
(
"Your certificate prevents you from unenrolling from this course"
))
CourseEnrollment
.
unenroll
(
user
,
course_id
)
CourseEnrollment
.
unenroll
(
user
,
course_id
)
REFUND_ORDER
.
send
(
sender
=
None
,
course_enrollment
=
enrollment
)
return
HttpResponse
()
return
HttpResponse
()
else
:
else
:
return
HttpResponseBadRequest
(
_
(
"Enrollment action is invalid"
))
return
HttpResponseBadRequest
(
_
(
"Enrollment action is invalid"
))
...
...
lms/djangoapps/commerce/signals.py
View file @
c74cd970
...
@@ -19,21 +19,19 @@ from openedx.core.djangoapps.commerce.utils import ecommerce_api_client, is_comm
...
@@ -19,21 +19,19 @@ from openedx.core.djangoapps.commerce.utils import ecommerce_api_client, is_comm
from
openedx.core.djangoapps.site_configuration
import
helpers
as
configuration_helpers
from
openedx.core.djangoapps.site_configuration
import
helpers
as
configuration_helpers
from
openedx.core.djangoapps.theming
import
helpers
as
theming_helpers
from
openedx.core.djangoapps.theming
import
helpers
as
theming_helpers
from
request_cache.middleware
import
RequestCache
from
request_cache.middleware
import
RequestCache
from
student.models
import
UNENROLL_DONE
from
student.models
import
REFUND_ORDER
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
# pylint: disable=unused-argument
# pylint: disable=unused-argument
@receiver
(
UNENROLL_DONE
)
@receiver
(
REFUND_ORDER
)
def
handle_
unenroll_done
(
sender
,
course_enrollment
=
None
,
skip_refund
=
Fals
e
,
**
kwargs
):
def
handle_
refund_order
(
sender
,
course_enrollment
=
Non
e
,
**
kwargs
):
"""
"""
Signal receiver for unenrollments, used to automatically initiate refunds
Signal receiver for unenrollments, used to automatically initiate refunds
when applicable.
when applicable.
N.B. this signal is also consumed by lms.djangoapps.shoppingcart.
"""
"""
if
not
is_commerce_service_configured
()
or
skip_refund
:
if
not
is_commerce_service_configured
():
return
return
if
course_enrollment
and
course_enrollment
.
refundable
():
if
course_enrollment
and
course_enrollment
.
refundable
():
...
...
lms/djangoapps/commerce/tests/test_signals.py
View file @
c74cd970
...
@@ -23,7 +23,7 @@ from commerce.signals import create_zendesk_ticket, generate_refund_notification
...
@@ -23,7 +23,7 @@ from commerce.signals import create_zendesk_ticket, generate_refund_notification
from
commerce.tests
import
JSON
from
commerce.tests
import
JSON
from
commerce.tests.mocks
import
mock_create_refund
,
mock_process_refund
from
commerce.tests.mocks
import
mock_create_refund
,
mock_process_refund
from
course_modes.models
import
CourseMode
from
course_modes.models
import
CourseMode
from
student.models
import
UNENROLL_DONE
from
student.models
import
REFUND_ORDER
from
student.tests.factories
import
CourseEnrollmentFactory
,
UserFactory
from
student.tests.factories
import
CourseEnrollmentFactory
,
UserFactory
ZENDESK_URL
=
'http://zendesk.example.com/'
ZENDESK_URL
=
'http://zendesk.example.com/'
...
@@ -35,7 +35,7 @@ ZENDESK_API_KEY = 'abc123'
...
@@ -35,7 +35,7 @@ ZENDESK_API_KEY = 'abc123'
@override_settings
(
ZENDESK_URL
=
ZENDESK_URL
,
ZENDESK_USER
=
ZENDESK_USER
,
ZENDESK_API_KEY
=
ZENDESK_API_KEY
)
@override_settings
(
ZENDESK_URL
=
ZENDESK_URL
,
ZENDESK_USER
=
ZENDESK_USER
,
ZENDESK_API_KEY
=
ZENDESK_API_KEY
)
class
TestRefundSignal
(
TestCase
):
class
TestRefundSignal
(
TestCase
):
"""
"""
Exercises logic triggered by the
UNENROLL_DONE
signal.
Exercises logic triggered by the
REFUND_ORDER
signal.
"""
"""
def
setUp
(
self
):
def
setUp
(
self
):
...
@@ -60,12 +60,12 @@ class TestRefundSignal(TestCase):
...
@@ -60,12 +60,12 @@ class TestRefundSignal(TestCase):
self
.
config
.
enable_automatic_refund_approval
=
True
self
.
config
.
enable_automatic_refund_approval
=
True
self
.
config
.
save
()
self
.
config
.
save
()
def
send_signal
(
self
,
skip_refund
=
False
):
def
send_signal
(
self
):
"""
"""
DRY helper: emit the
UNENROLL_DONE
signal, as is done in
DRY helper: emit the
REFUND_ORDER
signal, as is done in
common.djangoapps.student.models after a successful unenrollment.
common.djangoapps.student.models after a successful unenrollment.
"""
"""
UNENROLL_DONE
.
send
(
sender
=
None
,
course_enrollment
=
self
.
course_enrollment
,
skip_refund
=
skip_refund
)
REFUND_ORDER
.
send
(
sender
=
None
,
course_enrollment
=
self
.
course_enrollment
)
@override_settings
(
@override_settings
(
ECOMMERCE_PUBLIC_URL_ROOT
=
None
,
ECOMMERCE_PUBLIC_URL_ROOT
=
None
,
...
@@ -83,7 +83,7 @@ class TestRefundSignal(TestCase):
...
@@ -83,7 +83,7 @@ class TestRefundSignal(TestCase):
@mock.patch
(
'commerce.signals.refund_seat'
)
@mock.patch
(
'commerce.signals.refund_seat'
)
def
test_receiver
(
self
,
mock_refund_seat
):
def
test_receiver
(
self
,
mock_refund_seat
):
"""
"""
Ensure that the
UNENROLL_DONE
signal triggers correct calls to
Ensure that the
REFUND_ORDER
signal triggers correct calls to
refund_seat(), when it is appropriate to do so.
refund_seat(), when it is appropriate to do so.
TODO (jsa): ideally we would assert that the signal receiver got wired
TODO (jsa): ideally we would assert that the signal receiver got wired
...
@@ -94,11 +94,6 @@ class TestRefundSignal(TestCase):
...
@@ -94,11 +94,6 @@ class TestRefundSignal(TestCase):
self
.
assertTrue
(
mock_refund_seat
.
called
)
self
.
assertTrue
(
mock_refund_seat
.
called
)
self
.
assertEqual
(
mock_refund_seat
.
call_args
[
0
],
(
self
.
course_enrollment
,))
self
.
assertEqual
(
mock_refund_seat
.
call_args
[
0
],
(
self
.
course_enrollment
,))
# if skip_refund is set to True in the signal, we should not try to initiate a refund.
mock_refund_seat
.
reset_mock
()
self
.
send_signal
(
skip_refund
=
True
)
self
.
assertFalse
(
mock_refund_seat
.
called
)
# if the course_enrollment is not refundable, we should not try to initiate a refund.
# if the course_enrollment is not refundable, we should not try to initiate a refund.
mock_refund_seat
.
reset_mock
()
mock_refund_seat
.
reset_mock
()
self
.
course_enrollment
.
refundable
=
mock
.
Mock
(
return_value
=
False
)
self
.
course_enrollment
.
refundable
=
mock
.
Mock
(
return_value
=
False
)
...
...
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