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
cb6a4db1
Commit
cb6a4db1
authored
Jan 06, 2015
by
Awais Qureshi
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #6430 from edx/awais786/ECOM-662-decline-error
Awais786/ecom 662 decline error
parents
f6186aed
dfb366af
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
145 additions
and
52 deletions
+145
-52
lms/djangoapps/shoppingcart/processors/CyberSource2.py
+14
-0
lms/djangoapps/shoppingcart/processors/exceptions.py
+5
-0
lms/djangoapps/shoppingcart/processors/tests/test_CyberSource2.py
+62
-41
lms/djangoapps/shoppingcart/tests/payment_fake.py
+33
-4
lms/djangoapps/shoppingcart/tests/test_payment_fake.py
+11
-0
lms/templates/shoppingcart/test/fake_payment_page.html
+20
-7
No files found.
lms/djangoapps/shoppingcart/processors/CyberSource2.py
View file @
cb6a4db1
...
...
@@ -142,6 +142,11 @@ def verify_signatures(params):
if
params
.
get
(
'decision'
)
==
u'CANCEL'
:
raise
CCProcessorUserCancelled
()
# if the user decline the transaction
# if so, then auth_amount will not be passed back so we can't yet verify signatures
if
params
.
get
(
'decision'
)
==
u'DECLINE'
:
raise
CCProcessorUserDeclined
()
# Validate the signature to ensure that the message is from CyberSource
# and has not been tampered with.
signed_fields
=
params
.
get
(
'signed_field_names'
,
''
)
.
split
(
','
)
...
...
@@ -520,6 +525,15 @@ def _get_processor_exception_html(exception):
email
=
payment_support_email
)
)
elif
isinstance
(
exception
,
CCProcessorUserDeclined
):
return
_format_error_html
(
_
(
u"We're sorry, but this payment was declined. The items in your shopping cart have been saved. "
u"If you have any questions about this transaction, please contact us at {email}."
)
.
format
(
email
=
payment_support_email
)
)
else
:
return
_format_error_html
(
_
(
...
...
lms/djangoapps/shoppingcart/processors/exceptions.py
View file @
cb6a4db1
...
...
@@ -19,3 +19,8 @@ class CCProcessorWrongAmountException(CCProcessorException):
class
CCProcessorUserCancelled
(
CCProcessorException
):
pass
class
CCProcessorUserDeclined
(
CCProcessorException
):
"""Transaction declined."""
pass
lms/djangoapps/shoppingcart/processors/tests/test_CyberSource2.py
View file @
cb6a4db1
...
...
@@ -37,6 +37,7 @@ class CyberSource2Test(TestCase):
COST
=
"10.00"
CALLBACK_URL
=
"/test_callback_url"
FAILED_DECISIONS
=
[
"DECLINE"
,
"CANCEL"
,
"ERROR"
]
def
setUp
(
self
):
""" Create a user and an order. """
...
...
@@ -142,7 +143,7 @@ class CyberSource2Test(TestCase):
def
test_process_payment_rejected
(
self
):
# Simulate a callback from CyberSource indicating that the payment was rejected
params
=
self
.
_signed_callback_params
(
self
.
order
.
id
,
self
.
COST
,
self
.
COST
,
accepted
=
False
)
params
=
self
.
_signed_callback_params
(
self
.
order
.
id
,
self
.
COST
,
self
.
COST
,
decision
=
'REJECT'
)
result
=
process_postpay_callback
(
params
)
# Expect that we get an error message
...
...
@@ -263,7 +264,7 @@ class CyberSource2Test(TestCase):
def
_signed_callback_params
(
self
,
order_id
,
order_amount
,
paid_amount
,
accepted
=
True
,
signature
=
None
,
card_number
=
'xxxxxxxxxxxx1111'
,
decision
=
'ACCEPT'
,
signature
=
None
,
card_number
=
'xxxxxxxxxxxx1111'
,
first_name
=
'John'
):
"""
...
...
@@ -281,7 +282,7 @@ class CyberSource2Test(TestCase):
Keyword Args:
accepted (bool): Whether the payment was accepted or reject
ed.
decision (string): Whether the payment was accepted or rejected or declin
ed.
signature (string): If provided, use this value instead of calculating the signature.
card_numer (string): If provided, use this value instead of the default credit card number.
first_name (string): If provided, the first name of the user.
...
...
@@ -292,9 +293,51 @@ class CyberSource2Test(TestCase):
"""
# Parameters sent from CyberSource to our callback implementation
# These were captured from the CC test server.
signed_field_names
=
[
"transaction_id"
,
"decision"
,
"req_access_key"
,
"req_profile_id"
,
"req_transaction_uuid"
,
"req_transaction_type"
,
"req_reference_number"
,
"req_amount"
,
"req_currency"
,
"req_locale"
,
"req_payment_method"
,
"req_override_custom_receipt_page"
,
"req_bill_to_forename"
,
"req_bill_to_surname"
,
"req_bill_to_email"
,
"req_bill_to_address_line1"
,
"req_bill_to_address_city"
,
"req_bill_to_address_state"
,
"req_bill_to_address_country"
,
"req_bill_to_address_postal_code"
,
"req_card_number"
,
"req_card_type"
,
"req_card_expiry_date"
,
"message"
,
"reason_code"
,
"auth_avs_code"
,
"auth_avs_code_raw"
,
"auth_response"
,
"auth_amount"
,
"auth_code"
,
"auth_trans_ref_no"
,
"auth_time"
,
"bill_trans_ref_no"
,
"signed_field_names"
,
"signed_date_time"
]
# if decision is in FAILED_DECISIONS list then remove auth_amount from
# signed_field_names list.
if
decision
in
self
.
FAILED_DECISIONS
:
signed_field_names
.
remove
(
"auth_amount"
)
params
=
{
# Parameters that change based on the test
"decision"
:
"ACCEPT"
if
accepted
else
"REJECT"
,
"decision"
:
decision
,
"req_reference_number"
:
str
(
order_id
),
"req_amount"
:
order_amount
,
"auth_amount"
:
paid_amount
,
...
...
@@ -307,43 +350,7 @@ class CyberSource2Test(TestCase):
"req_card_expiry_date"
:
"01-2018"
,
"bill_trans_ref_no"
:
"85080648RYI23S6I"
,
"req_bill_to_address_state"
:
"MA"
,
"signed_field_names"
:
","
.
join
([
"transaction_id"
,
"decision"
,
"req_access_key"
,
"req_profile_id"
,
"req_transaction_uuid"
,
"req_transaction_type"
,
"req_reference_number"
,
"req_amount"
,
"req_currency"
,
"req_locale"
,
"req_payment_method"
,
"req_override_custom_receipt_page"
,
"req_bill_to_forename"
,
"req_bill_to_surname"
,
"req_bill_to_email"
,
"req_bill_to_address_line1"
,
"req_bill_to_address_city"
,
"req_bill_to_address_state"
,
"req_bill_to_address_country"
,
"req_bill_to_address_postal_code"
,
"req_card_number"
,
"req_card_type"
,
"req_card_expiry_date"
,
"message"
,
"reason_code"
,
"auth_avs_code"
,
"auth_avs_code_raw"
,
"auth_response"
,
"auth_amount"
,
"auth_code"
,
"auth_trans_ref_no"
,
"auth_time"
,
"bill_trans_ref_no"
,
"signed_field_names"
,
"signed_date_time"
]),
"signed_field_names"
:
","
.
join
(
signed_field_names
),
"req_payment_method"
:
"card"
,
"req_transaction_type"
:
"sale"
,
"auth_code"
:
"888888"
,
...
...
@@ -370,6 +377,11 @@ class CyberSource2Test(TestCase):
"req_access_key"
:
"abcd12345"
,
}
# if decision is in FAILED_DECISIONS list then remove the auth_amount from params dict
if
decision
in
self
.
FAILED_DECISIONS
:
del
params
[
"auth_amount"
]
# Calculate the signature
params
[
'signature'
]
=
signature
if
signature
is
not
None
else
self
.
_signature
(
params
)
return
params
...
...
@@ -398,3 +410,12 @@ class CyberSource2Test(TestCase):
in
params
[
'signed_field_names'
]
.
split
(
u","
)
])
)
def
test_process_payment_declined
(
self
):
# Simulate a callback from CyberSource indicating that the payment was declined
params
=
self
.
_signed_callback_params
(
self
.
order
.
id
,
self
.
COST
,
self
.
COST
,
decision
=
'DECLINE'
)
result
=
process_postpay_callback
(
params
)
# Expect that we get an error message
self
.
assertFalse
(
result
[
'success'
])
self
.
assertIn
(
u"payment was declined"
,
result
[
'error_html'
])
lms/djangoapps/shoppingcart/tests/payment_fake.py
View file @
cb6a4db1
...
...
@@ -78,7 +78,7 @@ class PaymentFakeView(View):
"""
new_status
=
request
.
body
if
new_status
not
in
[
"success"
,
"failure"
]:
if
new_status
not
in
[
"success"
,
"failure"
,
"decline"
]:
return
HttpResponseBadRequest
()
else
:
...
...
@@ -109,9 +109,17 @@ class PaymentFakeView(View):
"""
Calculate the POST params we want to send back to the client.
"""
if
cls
.
PAYMENT_STATUS_RESPONSE
==
"success"
:
decision
=
"ACCEPT"
elif
cls
.
PAYMENT_STATUS_RESPONSE
==
"decline"
:
decision
=
"DECLINE"
else
:
decision
=
"REJECT"
resp_params
=
{
# Indicate whether the payment was successful
"decision"
:
"ACCEPT"
if
cls
.
PAYMENT_STATUS_RESPONSE
==
"success"
else
"REJECT"
,
"decision"
:
decision
,
# Reflect back parameters we were sent by the client
"req_amount"
:
post_params
.
get
(
'amount'
),
...
...
@@ -170,6 +178,13 @@ class PaymentFakeView(View):
'bill_trans_ref_no'
,
'signed_field_names'
,
'signed_date_time'
]
# if decision is decline , cancel or error then remove auth_amount from signed_field.
# list and also delete from resp_params dict
if
decision
in
[
"DECLINE"
,
"CANCEL"
,
"ERROR"
]:
signed_fields
.
remove
(
'auth_amount'
)
del
resp_params
[
"auth_amount"
]
# Add the list of signed fields
resp_params
[
'signed_field_names'
]
=
","
.
join
(
signed_fields
)
...
...
@@ -202,13 +217,27 @@ class PaymentFakeView(View):
# Build the context dict used to render the HTML form,
# filling in values for the hidden input fields.
# These will be sent in the POST request to the callback URL.
post_params_success
=
self
.
response_post_params
(
post_params
)
# Build the context dict for decline form,
# remove the auth_amount value from here to
# reproduce exact response coming from actual postback call
post_params_decline
=
self
.
response_post_params
(
post_params
)
del
post_params_decline
[
"auth_amount"
]
post_params_decline
[
"decision"
]
=
'DECLINE'
context_dict
=
{
# URL to send the POST request to
"callback_url"
:
callback_url
,
# POST params embedded in the HTML form
'post_params'
:
self
.
response_post_params
(
post_params
)
# POST params embedded in the HTML success form
'post_params_success'
:
post_params_success
,
# POST params embedded in the HTML decline form
'post_params_decline'
:
post_params_decline
}
return
render_to_response
(
'shoppingcart/test/fake_payment_page.html'
,
context_dict
)
lms/djangoapps/shoppingcart/tests/test_payment_fake.py
View file @
cb6a4db1
...
...
@@ -92,6 +92,17 @@ class PaymentFakeViewTest(TestCase):
# Generate shoppingcart signatures
post_params
=
sign
(
self
.
CLIENT_POST_PARAMS
)
# Configure the view to declined payments
resp
=
self
.
client
.
put
(
'/shoppingcart/payment_fake'
,
data
=
"decline"
,
content_type
=
'text/plain'
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
# Check that the decision is "DECLINE"
resp_params
=
PaymentFakeView
.
response_post_params
(
post_params
)
self
.
assertEqual
(
resp_params
.
get
(
'decision'
),
'DECLINE'
)
# Configure the view to fail payments
resp
=
self
.
client
.
put
(
'/shoppingcart/payment_fake'
,
...
...
lms/templates/shoppingcart/test/fake_payment_page.html
View file @
cb6a4db1
<html>
<head><title>
Payment Form
</title></head>
<head><title>
Payment Form
</title>
</head>
<body>
<p>
Payment page
</p>
<form
name=
"input"
action=
"${callback_url}"
method=
"post"
>
% for name, value in post_params.items():
<p>
Payment page
</p>
<form
name=
"input"
action=
"${callback_url}"
method=
"post"
>
% for name, value in post_params_success.items():
<input
type=
"hidden"
name=
"${name}"
value=
"${value}"
>
% endfor
<input
type=
"submit"
value=
"Submit"
>
</form>
% endfor
<input
type=
"submit"
value=
"Submit"
>
</form>
<form
name=
"frm_decline"
action=
"${callback_url}"
method=
"post"
>
% for name, value in post_params_decline.items():
<input
type=
"hidden"
name=
"${name}"
value=
"${value}"
>
% endfor
<input
type=
"submit"
value=
"Decline"
id=
"decline"
>
</form>
</body>
</html>
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