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
e4e22f0f
Commit
e4e22f0f
authored
Aug 09, 2013
by
Jason Bau
Committed by
Diana Huang
Aug 22, 2013
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Lots more verification of CyberSource reply + receipt generation
parent
41b9f9f0
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
366 additions
and
18 deletions
+366
-18
lms/djangoapps/shoppingcart/migrations/0003_auto__add_field_order_bill_to_state.py
+97
-0
lms/djangoapps/shoppingcart/models.py
+15
-2
lms/djangoapps/shoppingcart/processors/CyberSource.py
+109
-4
lms/djangoapps/shoppingcart/processors/__init__.py
+21
-1
lms/djangoapps/shoppingcart/processors/exceptions.py
+12
-0
lms/djangoapps/shoppingcart/urls.py
+3
-1
lms/djangoapps/shoppingcart/views.py
+47
-6
lms/envs/aws.py
+1
-1
lms/envs/common.py
+1
-0
lms/templates/shoppingcart/list.html
+4
-3
lms/templates/shoppingcart/receipt.html
+56
-0
No files found.
lms/djangoapps/shoppingcart/migrations/0003_auto__add_field_order_bill_to_state.py
0 → 100644
View file @
e4e22f0f
# -*- coding: utf-8 -*-
import
datetime
from
south.db
import
db
from
south.v2
import
SchemaMigration
from
django.db
import
models
class
Migration
(
SchemaMigration
):
def
forwards
(
self
,
orm
):
# Adding field 'Order.bill_to_state'
db
.
add_column
(
'shoppingcart_order'
,
'bill_to_state'
,
self
.
gf
(
'django.db.models.fields.CharField'
)(
max_length
=
8
,
null
=
True
,
blank
=
True
),
keep_default
=
False
)
def
backwards
(
self
,
orm
):
# Deleting field 'Order.bill_to_state'
db
.
delete_column
(
'shoppingcart_order'
,
'bill_to_state'
)
models
=
{
'auth.group'
:
{
'Meta'
:
{
'object_name'
:
'Group'
},
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'80'
}),
'permissions'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.Permission']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
})
},
'auth.permission'
:
{
'Meta'
:
{
'ordering'
:
"('content_type__app_label', 'content_type__model', 'codename')"
,
'unique_together'
:
"(('content_type', 'codename'),)"
,
'object_name'
:
'Permission'
},
'codename'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'content_type'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['contenttypes.ContentType']"
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'50'
})
},
'auth.user'
:
{
'Meta'
:
{
'object_name'
:
'User'
},
'date_joined'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'email'
:
(
'django.db.models.fields.EmailField'
,
[],
{
'max_length'
:
'75'
,
'blank'
:
'True'
}),
'first_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'groups'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.Group']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'is_active'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
'is_staff'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'is_superuser'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'last_login'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'last_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'password'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'128'
}),
'user_permissions'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.Permission']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
}),
'username'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'30'
})
},
'contenttypes.contenttype'
:
{
'Meta'
:
{
'ordering'
:
"('name',)"
,
'unique_together'
:
"(('app_label', 'model'),)"
,
'object_name'
:
'ContentType'
,
'db_table'
:
"'django_content_type'"
},
'app_label'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'model'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
})
},
'shoppingcart.order'
:
{
'Meta'
:
{
'object_name'
:
'Order'
},
'bill_to_cardtype'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'32'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'bill_to_ccnum'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'8'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'bill_to_city'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'64'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'bill_to_country'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'64'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'bill_to_first'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'64'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'bill_to_last'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'64'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'bill_to_postalcode'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'16'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'bill_to_state'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'8'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'bill_to_street1'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'128'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'bill_to_street2'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'128'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'processor_reply_dump'
:
(
'django.db.models.fields.TextField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'purchase_time'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'status'
:
(
'django.db.models.fields.CharField'
,
[],
{
'default'
:
"'cart'"
,
'max_length'
:
'32'
}),
'user'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['auth.User']"
})
},
'shoppingcart.orderitem'
:
{
'Meta'
:
{
'object_name'
:
'OrderItem'
},
'currency'
:
(
'django.db.models.fields.CharField'
,
[],
{
'default'
:
"'usd'"
,
'max_length'
:
'8'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'line_cost'
:
(
'django.db.models.fields.FloatField'
,
[],
{
'default'
:
'0.0'
}),
'line_desc'
:
(
'django.db.models.fields.CharField'
,
[],
{
'default'
:
"'Misc. Item'"
,
'max_length'
:
'1024'
}),
'order'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['shoppingcart.Order']"
}),
'qty'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'default'
:
'1'
}),
'status'
:
(
'django.db.models.fields.CharField'
,
[],
{
'default'
:
"'cart'"
,
'max_length'
:
'32'
}),
'unit_cost'
:
(
'django.db.models.fields.FloatField'
,
[],
{
'default'
:
'0.0'
}),
'user'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['auth.User']"
})
},
'shoppingcart.paidcourseregistration'
:
{
'Meta'
:
{
'object_name'
:
'PaidCourseRegistration'
,
'_ormbases'
:
[
'shoppingcart.OrderItem'
]},
'course_id'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'128'
,
'db_index'
:
'True'
}),
'orderitem_ptr'
:
(
'django.db.models.fields.related.OneToOneField'
,
[],
{
'to'
:
"orm['shoppingcart.OrderItem']"
,
'unique'
:
'True'
,
'primary_key'
:
'True'
})
}
}
complete_apps
=
[
'shoppingcart'
]
\ No newline at end of file
lms/djangoapps/shoppingcart/models.py
View file @
e4e22f0f
...
...
@@ -32,6 +32,7 @@ class Order(models.Model):
bill_to_street1
=
models
.
CharField
(
max_length
=
128
,
null
=
True
,
blank
=
True
)
bill_to_street2
=
models
.
CharField
(
max_length
=
128
,
null
=
True
,
blank
=
True
)
bill_to_city
=
models
.
CharField
(
max_length
=
64
,
null
=
True
,
blank
=
True
)
bill_to_state
=
models
.
CharField
(
max_length
=
8
,
null
=
True
,
blank
=
True
)
bill_to_postalcode
=
models
.
CharField
(
max_length
=
16
,
null
=
True
,
blank
=
True
)
bill_to_country
=
models
.
CharField
(
max_length
=
64
,
null
=
True
,
blank
=
True
)
bill_to_ccnum
=
models
.
CharField
(
max_length
=
8
,
null
=
True
,
blank
=
True
)
# last 4 digits
...
...
@@ -49,7 +50,7 @@ class Order(models.Model):
@property
def
total_cost
(
self
):
return
sum
([
i
.
line_cost
for
i
in
self
.
orderitem_set
.
all
(
)])
return
sum
([
i
.
line_cost
for
i
in
self
.
orderitem_set
.
filter
(
status
=
self
.
status
)])
@property
def
currency
(
self
):
...
...
@@ -60,13 +61,25 @@ class Order(models.Model):
else
:
return
items
[
0
]
.
currency
def
purchase
(
self
):
def
purchase
(
self
,
first
=
''
,
last
=
''
,
street1
=
''
,
street2
=
''
,
city
=
''
,
state
=
''
,
postalcode
=
''
,
country
=
''
,
ccnum
=
''
,
cardtype
=
''
,
processor_reply_dump
=
''
):
"""
Call to mark this order as purchased. Iterates through its OrderItems and calls
their purchased_callback
"""
self
.
status
=
'purchased'
self
.
purchase_time
=
datetime
.
now
(
pytz
.
utc
)
self
.
bill_to_first
=
first
self
.
bill_to_last
=
last
self
.
bill_to_street1
=
street1
self
.
bill_to_street2
=
street2
self
.
bill_to_city
=
city
self
.
bill_to_state
=
state
self
.
bill_to_postalcode
=
postalcode
self
.
bill_to_country
=
country
self
.
bill_to_ccnum
=
ccnum
self
.
bill_to_cardtype
=
cardtype
self
.
processor_reply_dump
=
processor_reply_dump
self
.
save
()
for
item
in
self
.
orderitem_set
.
all
():
item
.
status
=
'purchased'
...
...
lms/djangoapps/shoppingcart/processors/CyberSource.py
View file @
e4e22f0f
### Implementation of support for the Cybersource Credit card processor
### The name of this file should be used as the key of the dict in the CC_PROCESSOR setting
### Implementes interface as specified by __init__.py
import
time
import
hmac
import
binascii
from
collections
import
OrderedDict
import
re
import
json
from
collections
import
OrderedDict
,
defaultdict
from
hashlib
import
sha1
from
django.conf
import
settings
from
django.utils.translation
import
ugettext
as
_
from
mitxmako.shortcuts
import
render_to_string
from
shoppingcart.models
import
Order
from
.exceptions
import
CCProcessorDataException
,
CCProcessorWrongAmountException
shared_secret
=
settings
.
CC_PROCESSOR
[
'CyberSource'
]
.
get
(
'SHARED_SECRET'
,
''
)
merchant_id
=
settings
.
CC_PROCESSOR
[
'CyberSource'
]
.
get
(
'MERCHANT_ID'
,
''
)
...
...
@@ -41,6 +47,7 @@ def sign(params):
return
params
def
verify
(
params
):
"""
Verify the signatures accompanying the POST back from Cybersource Hosted Order Page
...
...
@@ -54,7 +61,11 @@ def verify(params):
return
False
return
hash
(
data
)
==
returned_sig
def
render_purchase_form_html
(
cart
,
user
):
"""
Renders the HTML of the hidden POST form that must be used to initiate a purchase with CyberSource
"""
total_cost
=
cart
.
total_cost
amount
=
"{0:0.2f}"
.
format
(
total_cost
)
cart_items
=
cart
.
orderitem_set
.
all
()
...
...
@@ -64,7 +75,6 @@ def render_purchase_form_html(cart, user):
params
[
'currency'
]
=
cart
.
currency
params
[
'orderPage_transactionType'
]
=
'sale'
params
[
'orderNumber'
]
=
"{0:d}"
.
format
(
cart
.
id
)
params
[
'billTo_email'
]
=
user
.
email
idx
=
1
for
item
in
cart_items
:
prefix
=
"item_{0:d}_"
.
format
(
idx
)
...
...
@@ -78,4 +88,100 @@ def render_purchase_form_html(cart, user):
return
render_to_string
(
'shoppingcart/cybersource_form.html'
,
{
'action'
:
purchase_endpoint
,
'params'
:
signed_param_dict
,
})
\ No newline at end of file
})
def
payment_accepted
(
params
):
"""
Check that cybersource has accepted the payment
"""
#make sure required keys are present and convert their values to the right type
valid_params
=
{}
for
key
,
type
in
[(
'orderNumber'
,
int
),
(
'ccAuthReply_amount'
,
float
),
(
'orderCurrency'
,
str
),
(
'decision'
,
str
)]:
if
key
not
in
params
:
raise
CCProcessorDataException
(
_
(
"The payment processor did not return a required parameter: {0}"
.
format
(
key
))
)
try
:
valid_params
[
key
]
=
type
(
params
[
key
])
except
ValueError
:
raise
CCProcessorDataException
(
_
(
"The payment processor returned a badly-typed value {0} for param {1}."
.
format
(
params
[
key
],
key
))
)
try
:
order
=
Order
.
objects
.
get
(
id
=
valid_params
[
'orderNumber'
])
except
Order
.
DoesNotExist
:
raise
CCProcessorDataException
(
_
(
"The payment processor accepted an order whose number is not in our system."
))
if
valid_params
[
'decision'
]
==
'ACCEPT'
:
if
valid_params
[
'ccAuthReply_amount'
]
==
order
.
total_cost
and
valid_params
[
'orderCurrency'
]
==
order
.
currency
:
return
{
'accepted'
:
True
,
'amt_charged'
:
valid_params
[
'ccAuthReply_amount'
],
'currency'
:
valid_params
[
'orderCurrency'
],
'order'
:
order
}
else
:
raise
CCProcessorWrongAmountException
(
_
(
"The amount charged by the processor {0} {1} is different than the total cost of the order {2} {3}."
\
.
format
(
valid_params
[
'ccAuthReply_amount'
],
valid_params
[
'orderCurrency'
],
order
.
total_cost
,
order
.
currency
))
)
else
:
return
{
'accepted'
:
False
,
'amt_charged'
:
0
,
'currency'
:
'usd'
,
'order'
:
None
}
def
record_purchase
(
params
,
order
):
"""
Record the purchase and run purchased_callbacks
"""
ccnum_str
=
params
.
get
(
'card_accountNumber'
,
''
)
m
=
re
.
search
(
"
\
d"
,
ccnum_str
)
if
m
:
ccnum
=
ccnum_str
[
m
.
start
():]
else
:
ccnum
=
"####"
order
.
purchase
(
first
=
params
.
get
(
'billTo_firstName'
,
''
),
last
=
params
.
get
(
'billTo_lastName'
,
''
),
street1
=
params
.
get
(
'billTo_street1'
,
''
),
street2
=
params
.
get
(
'billTo_street2'
,
''
),
city
=
params
.
get
(
'billTo_city'
,
''
),
state
=
params
.
get
(
'billTo_state'
,
''
),
country
=
params
.
get
(
'billTo_country'
,
''
),
postalcode
=
params
.
get
(
'billTo_postalCode'
,
''
),
ccnum
=
ccnum
,
cardtype
=
CARDTYPE_MAP
[
params
.
get
(
'card_cardType'
,
'UNKNOWN'
)],
processor_reply_dump
=
json
.
dumps
(
params
)
)
CARDTYPE_MAP
=
defaultdict
(
lambda
:
"UNKNOWN"
)
CARDTYPE_MAP
.
update
(
{
'001'
:
'Visa'
,
'002'
:
'MasterCard'
,
'003'
:
'American Express'
,
'004'
:
'Discover'
,
'005'
:
'Diners Club'
,
'006'
:
'Carte Blanche'
,
'007'
:
'JCB'
,
'014'
:
'EnRoute'
,
'021'
:
'JAL'
,
'024'
:
'Maestro'
,
'031'
:
'Delta'
,
'033'
:
'Visa Electron'
,
'034'
:
'Dankort'
,
'035'
:
'Laser'
,
'036'
:
'Carte Bleue'
,
'037'
:
'Carta Si'
,
'042'
:
'Maestro'
,
'043'
:
'GE Money UK card'
}
)
lms/djangoapps/shoppingcart/processors/__init__.py
View file @
e4e22f0f
...
...
@@ -3,7 +3,12 @@ from django.conf import settings
### Now code that determines, using settings, which actual processor implementation we're using.
processor_name
=
settings
.
CC_PROCESSOR
.
keys
()[
0
]
module
=
__import__
(
'shoppingcart.processors.'
+
processor_name
,
fromlist
=
[
'sign'
,
'verify'
,
'render_purchase_form_html'
])
fromlist
=
[
'sign'
,
'verify'
,
'render_purchase_form_html'
'payment_accepted'
,
'record_purchase'
,
])
def
sign
(
*
args
,
**
kwargs
):
"""
...
...
@@ -32,3 +37,18 @@ def render_purchase_form_html(*args, **kwargs):
Returns the HTML as a string
"""
return
module
.
render_purchase_form_html
(
*
args
,
**
kwargs
)
def
payment_accepted
(
*
args
,
**
kwargs
):
"""
Given params returned by the CC processor, check that processor has accepted the payment
Returns a dict of {accepted:bool, amt_charged:float, currency:str, order:Order}
"""
return
module
.
payment_accepted
(
*
args
,
**
kwargs
)
def
record_purchase
(
*
args
,
**
kwargs
):
"""
Given params returned by the CC processor, record that the purchase has occurred in
the database and also run callbacks
"""
return
module
.
record_purchase
(
*
args
,
**
kwargs
)
lms/djangoapps/shoppingcart/processors/exceptions.py
0 → 100644
View file @
e4e22f0f
class
PaymentException
(
Exception
):
pass
class
CCProcessorException
(
PaymentException
):
pass
class
CCProcessorDataException
(
CCProcessorException
):
pass
class
CCProcessorWrongAmountException
(
PaymentException
):
pass
\ No newline at end of file
lms/djangoapps/shoppingcart/urls.py
View file @
e4e22f0f
...
...
@@ -7,5 +7,6 @@ urlpatterns = patterns('shoppingcart.views', # nopep8
url
(
r'^clear/$'
,
'clear_cart'
),
url
(
r'^remove_item/$'
,
'remove_item'
),
url
(
r'^purchased/$'
,
'purchased'
),
url
(
r'^receipt/$'
,
'receipt'
),
url
(
r'^postpay_accept_callback/$'
,
'postpay_accept_callback'
),
url
(
r'^receipt/(?P<ordernum>[0-9]*)/$'
,
'show_receipt'
),
)
\ No newline at end of file
lms/djangoapps/shoppingcart/views.py
View file @
e4e22f0f
import
logging
from
django.http
import
HttpResponse
,
HttpResponseRedirect
from
django.http
import
HttpResponse
,
HttpResponseRedirect
,
Http404
from
django.core.urlresolvers
import
reverse
from
django.views.decorators.csrf
import
csrf_exempt
from
django.contrib.auth.decorators
import
login_required
from
mitxmako.shortcuts
import
render_to_response
from
.models
import
*
from
.processors
import
verify
,
render_purchase_form_html
from
.processors
import
verify
,
payment_accepted
,
render_purchase_form_html
,
record_purchase
from
.processors.exceptions
import
CCProcessorDataException
,
CCProcessorWrongAmountException
log
=
logging
.
getLogger
(
"shoppingcart"
)
...
...
@@ -60,13 +62,52 @@ def remove_item(request):
return
HttpResponse
(
'OK'
)
@csrf_exempt
def
receipt
(
request
):
def
postpay_accept_callback
(
request
):
"""
Receives the POST-back from processor and performs the validation and displays a receipt
and does some other stuff
HANDLES THE ACCEPT AND REVIEW CASES
"""
if
verify
(
request
.
POST
.
dict
()):
return
HttpResponse
(
"Validated"
)
# TODO: Templates and logic for all error cases and the REVIEW CASE
params
=
request
.
POST
.
dict
()
if
verify
(
params
):
try
:
result
=
payment_accepted
(
params
)
if
result
[
'accepted'
]:
# ACCEPTED CASE first
record_purchase
(
params
,
result
[
'order'
])
#render_receipt
return
HttpResponseRedirect
(
reverse
(
'shoppingcart.views.show_receipt'
,
args
=
[
result
[
'order'
]
.
id
]))
else
:
return
HttpResponse
(
"CC Processor has not accepted the payment."
)
except
CCProcessorWrongAmountException
:
return
HttpResponse
(
"Charged the wrong amount, contact our user support"
)
except
CCProcessorDataException
:
return
HttpResponse
(
"Exception: the processor returned invalid data"
)
else
:
return
HttpResponse
(
"Not Validated"
)
return
HttpResponse
(
"There has been a communication problem blah blah. Not Validated"
)
def
show_receipt
(
request
,
ordernum
):
"""
Displays a receipt for a particular order.
404 if order is not yet purchased or request.user != order.user
"""
try
:
order
=
Order
.
objects
.
get
(
id
=
ordernum
)
except
Order
.
DoesNotExist
:
raise
Http404
(
'Order not found!'
)
if
order
.
user
!=
request
.
user
or
order
.
status
!=
'purchased'
:
raise
Http404
(
'Order not found!'
)
order_items
=
order
.
orderitem_set
.
all
()
any_refunds
=
"refunded"
in
[
i
.
status
for
i
in
order_items
]
return
render_to_response
(
'shoppingcart/receipt.html'
,
{
'order'
:
order
,
'order_items'
:
order_items
,
'any_refunds'
:
any_refunds
})
def
show_orders
(
request
):
"""
Displays all orders of a user
"""
lms/envs/aws.py
View file @
e4e22f0f
...
...
@@ -127,6 +127,7 @@ SERVER_EMAIL = ENV_TOKENS.get('SERVER_EMAIL', SERVER_EMAIL)
TECH_SUPPORT_EMAIL
=
ENV_TOKENS
.
get
(
'TECH_SUPPORT_EMAIL'
,
TECH_SUPPORT_EMAIL
)
CONTACT_EMAIL
=
ENV_TOKENS
.
get
(
'CONTACT_EMAIL'
,
CONTACT_EMAIL
)
BUGS_EMAIL
=
ENV_TOKENS
.
get
(
'BUGS_EMAIL'
,
BUGS_EMAIL
)
PAYMENT_SUPPORT_EMAIL
=
ENV_TOKENS
.
get
(
'PAYMENT_SUPPORT_EMAIL'
,
PAYMENT_SUPPORT_EMAIL
)
#Theme overrides
THEME_NAME
=
ENV_TOKENS
.
get
(
'THEME_NAME'
,
None
)
...
...
@@ -190,7 +191,6 @@ SEGMENT_IO_LMS_KEY = AUTH_TOKENS.get('SEGMENT_IO_LMS_KEY')
if
SEGMENT_IO_LMS_KEY
:
MITX_FEATURES
[
'SEGMENT_IO_LMS'
]
=
ENV_TOKENS
.
get
(
'SEGMENT_IO_LMS'
,
False
)
CC_PROCESSOR
=
AUTH_TOKENS
.
get
(
'CC_PROCESSOR'
,
CC_PROCESSOR
)
SECRET_KEY
=
AUTH_TOKENS
[
'SECRET_KEY'
]
...
...
lms/envs/common.py
View file @
e4e22f0f
...
...
@@ -432,6 +432,7 @@ ZENDESK_USER = None
ZENDESK_API_KEY
=
None
##### shoppingcart Payment #####
PAYMENT_SUPPORT_EMAIL
=
'payment@edx.org'
##### Using cybersource by default #####
CC_PROCESSOR
=
{
'CyberSource'
:
{
...
...
lms/templates/shoppingcart/list.html
View file @
e4e22f0f
...
...
@@ -7,10 +7,11 @@
<
%
block
name=
"title"
><title>
${_("Your Shopping Cart")}
</title></
%
block>
<section
class=
"container cart-list"
>
<h2>
${_("Your selected items:")}
</h2>
% if shoppingcart_items:
<table>
<thead>
<tr>
<td>
Qty
</td><td>
Description
</td><td>
Unit Price
</td><td>
Price
</td><td>
Currency
</td>
</tr>
<tr>
${_("
<td>
Quantity
</td><td>
Description
</td><td>
Unit Price
</td><td>
Price
</td><td>
Currency
</td>
")}
</tr>
</thead>
<tbody>
% for item in shoppingcart_items:
...
...
@@ -19,7 +20,7 @@
<td>
${item.currency.upper()}
</td>
<td><a
data-item-id=
"${item.id}"
class=
'remove_line_item'
href=
'#'
>
[x]
</a></td></tr>
% endfor
<tr><td></td><td></td><td></td><td>
Total Amount
</td></tr>
<tr><td></td><td></td><td></td><td>
${_("Total Amount")}
</td></tr>
<tr><td></td><td></td><td></td><td>
${amount}
</td></tr>
</tbody>
...
...
@@ -27,7 +28,7 @@
${form_html}
% else:
<p>
You have selected no items for purchase.
</p>
<p>
${_("You have selected no items for purchase.")}
</p>
% endif
</section>
...
...
lms/templates/shoppingcart/receipt.html
0 → 100644
View file @
e4e22f0f
<
%!
from
django
.
utils
.
translation
import
ugettext
as
_
%
>
<
%!
from
django
.
core
.
urlresolvers
import
reverse
%
>
<
%!
from
django
.
conf
import
settings
%
>
<
%
inherit
file=
"../main.html"
/>
<
%
block
name=
"title"
><title>
${_("Receipt for Order")} ${order.id}
</title></
%
block>
<section
class=
"container cart-list"
>
<p><h1>
${_(settings.PLATFORM_NAME + " (" + settings.SITE_NAME + ")" + " Electronic Receipt")}
</h1></p>
<h2>
${_("Order #")}${order.id}
</h2>
<h2>
${_("Date:")} ${order.purchase_time.date().isoformat()}
</h2>
<h2>
${_("Items ordered:")}
</h2>
<table>
<thead>
<tr>
${_("
<td>
Qty
</td><td>
Description
</td><td>
Unit Price
</td><td>
Price
</td><td>
Currency
</td>
")}
</tr>
</thead>
<tbody>
% for item in order_items:
<tr>
% if item.status == "purchased":
<td>
${item.qty}
</td><td>
${item.line_desc}
</td>
<td>
${"{0:0.2f}".format(item.unit_cost)}
</td>
<td>
${"{0:0.2f}".format(item.line_cost)}
</td>
<td>
${item.currency.upper()}
</td></tr>
% elif item.status == "refunded":
<td><del>
${item.qty}
</del></td><td><del>
${item.line_desc}
</del></td>
<td><del>
${"{0:0.2f}".format(item.unit_cost)}
</del></td>
<td><del>
${"{0:0.2f}".format(item.line_cost)}
</del></td>
<td><del>
${item.currency.upper()}
</del></td></tr>
% endif
% endfor
<tr><td></td><td></td><td></td><td>
${_("Total Amount")}
</td></tr>
<tr><td></td><td></td><td></td><td>
${"{0:0.2f}".format(order.total_cost)}
</td></tr>
</tbody>
</table>
% if any_refunds:
<p>
${_("Note: items with strikethough like ")}
<del>
this
</del>
${_(" have been refunded.")}
</p>
% endif
<h2>
${_("Billed To:")}
</h2>
<p>
${order.bill_to_cardtype} ${_("#:")} ${order.bill_to_ccnum}
<br
/>
${order.bill_to_first} ${order.bill_to_last}
<br
/>
${order.bill_to_street1}
<br
/>
${order.bill_to_street2}
<br
/>
${order.bill_to_city}, ${order.bill_to_state} ${order.bill_to_postalcode}
<br
/>
${order.bill_to_country.upper()}
<br
/>
</p>
</section>
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