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
e01699f3
Commit
e01699f3
authored
Jul 05, 2016
by
Vedran Karacic
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Set coupon custom code lower bound limit to 1.
parent
70915da6
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
50 additions
and
46 deletions
+50
-46
ecommerce/extensions/api/v2/tests/views/test_coupons.py
+10
-20
ecommerce/extensions/api/v2/views/coupons.py
+27
-24
ecommerce/static/js/models/coupon_model.js
+3
-2
ecommerce/static/js/test/specs/models/coupon_model_spec.js
+10
-0
No files found.
ecommerce/extensions/api/v2/tests/views/test_coupons.py
View file @
e01699f3
...
@@ -9,7 +9,6 @@ import ddt
...
@@ -9,7 +9,6 @@ import ddt
import
httpretty
import
httpretty
import
pytz
import
pytz
from
django.core.urlresolvers
import
reverse
from
django.core.urlresolvers
import
reverse
from
django.db.utils
import
IntegrityError
from
django.test
import
RequestFactory
from
django.test
import
RequestFactory
from
oscar.apps.catalogue.categories
import
create_from_breadcrumbs
from
oscar.apps.catalogue.categories
import
create_from_breadcrumbs
from
oscar.core.loading
import
get_class
,
get_model
from
oscar.core.loading
import
get_class
,
get_model
...
@@ -189,25 +188,6 @@ class CouponViewSetTest(CouponMixin, CourseCatalogTestMixin, TestCase):
...
@@ -189,25 +188,6 @@ class CouponViewSetTest(CouponMixin, CourseCatalogTestMixin, TestCase):
self
.
assertEqual
(
custom_coupon
.
attr
.
coupon_vouchers
.
vouchers
.
count
(),
1
)
self
.
assertEqual
(
custom_coupon
.
attr
.
coupon_vouchers
.
vouchers
.
count
(),
1
)
self
.
assertEqual
(
custom_coupon
.
attr
.
coupon_vouchers
.
vouchers
.
first
()
.
code
,
'CUSTOMCODE'
)
self
.
assertEqual
(
custom_coupon
.
attr
.
coupon_vouchers
.
vouchers
.
first
()
.
code
,
'CUSTOMCODE'
)
def
test_custom_code_integrity_error
(
self
):
"""Test custom coupon code duplication."""
self
.
coupon_data
.
update
({
'code'
:
'CUSTOMCODE'
,
'quantity'
:
1
,
})
CouponViewSet
()
.
create_coupon_product
(
title
=
'Custom coupon'
,
price
=
100
,
data
=
self
.
coupon_data
)
with
self
.
assertRaises
(
IntegrityError
):
CouponViewSet
()
.
create_coupon_product
(
title
=
'Coupon with integrity issue'
,
price
=
100
,
data
=
self
.
coupon_data
)
def
test_coupon_note
(
self
):
def
test_coupon_note
(
self
):
"""Test creating a coupon with a note."""
"""Test creating a coupon with a note."""
self
.
coupon_data
.
update
({
self
.
coupon_data
.
update
({
...
@@ -376,6 +356,16 @@ class CouponViewSetFunctionalTest(CouponMixin, CourseCatalogTestMixin, CourseCat
...
@@ -376,6 +356,16 @@ class CouponViewSetFunctionalTest(CouponMixin, CourseCatalogTestMixin, CourseCat
coupon_data
=
json
.
loads
(
response
.
content
)[
'results'
][
0
]
coupon_data
=
json
.
loads
(
response
.
content
)[
'results'
][
0
]
self
.
assertEqual
(
coupon_data
[
'title'
],
'Test coupon'
)
self
.
assertEqual
(
coupon_data
[
'title'
],
'Test coupon'
)
def
test_already_existing_code
(
self
):
"""Test custom coupon code duplication."""
self
.
data
.
update
({
'code'
:
'CUSTOMCODE'
,
'quantity'
:
1
,
})
self
.
client
.
post
(
COUPONS_LINK
,
data
=
self
.
data
,
format
=
'json'
)
response
=
self
.
client
.
post
(
COUPONS_LINK
,
data
=
self
.
data
,
format
=
'json'
)
self
.
assertEqual
(
response
.
status_code
,
400
)
def
test_update
(
self
):
def
test_update
(
self
):
"""Test updating a coupon."""
"""Test updating a coupon."""
coupon
=
Product
.
objects
.
get
(
title
=
'Test coupon'
)
coupon
=
Product
.
objects
.
get
(
title
=
'Test coupon'
)
...
...
ecommerce/extensions/api/v2/views/coupons.py
View file @
e01699f3
...
@@ -6,7 +6,6 @@ from decimal import Decimal
...
@@ -6,7 +6,6 @@ from decimal import Decimal
import
dateutil.parser
import
dateutil.parser
from
django.conf
import
settings
from
django.conf
import
settings
from
django.db
import
transaction
from
django.db
import
transaction
from
django.db.utils
import
IntegrityError
from
django.http
import
Http404
from
django.http
import
Http404
from
django.shortcuts
import
get_object_or_404
from
django.shortcuts
import
get_object_or_404
from
oscar.core.loading
import
get_model
from
oscar.core.loading
import
get_model
...
@@ -106,6 +105,8 @@ class CouponViewSet(EdxOrderPlacementMixin, viewsets.ModelViewSet):
...
@@ -106,6 +105,8 @@ class CouponViewSet(EdxOrderPlacementMixin, viewsets.ModelViewSet):
Returns:
Returns:
200 if the order was created successfully; the basket ID is included in the response
200 if the order was created successfully; the basket ID is included in the response
body along with the order ID and payment information.
body along with the order ID and payment information.
400 if a custom code is received that already exists,
if a course mode is selected that is not supported.
401 if an unauthenticated request is denied permission to access the endpoint.
401 if an unauthenticated request is denied permission to access the endpoint.
429 if the client has made requests at a rate exceeding that allowed by the configured rate limit.
429 if the client has made requests at a rate exceeding that allowed by the configured rate limit.
500 if an error occurs when attempting to create a coupon.
500 if an error occurs when attempting to create a coupon.
...
@@ -130,6 +131,16 @@ class CouponViewSet(EdxOrderPlacementMixin, viewsets.ModelViewSet):
...
@@ -130,6 +131,16 @@ class CouponViewSet(EdxOrderPlacementMixin, viewsets.ModelViewSet):
catalog_query
=
request
.
data
.
get
(
CATALOG_QUERY
)
catalog_query
=
request
.
data
.
get
(
CATALOG_QUERY
)
course_seat_types
=
request
.
data
.
get
(
COURSE_SEAT_TYPES
)
course_seat_types
=
request
.
data
.
get
(
COURSE_SEAT_TYPES
)
if
code
:
try
:
Voucher
.
objects
.
get
(
code
=
code
)
return
Response
(
'A coupon with code {code} already exists.'
.
format
(
code
=
code
),
status
=
status
.
HTTP_400_BAD_REQUEST
)
except
Voucher
.
DoesNotExist
:
pass
invoice_data
=
self
.
retrieve_invoice_data
(
request
.
data
)
invoice_data
=
self
.
retrieve_invoice_data
(
request
.
data
)
if
course_seat_types
:
if
course_seat_types
:
...
@@ -218,10 +229,6 @@ class CouponViewSet(EdxOrderPlacementMixin, viewsets.ModelViewSet):
...
@@ -218,10 +229,6 @@ class CouponViewSet(EdxOrderPlacementMixin, viewsets.ModelViewSet):
Returns:
Returns:
A coupon product object.
A coupon product object.
Raises:
IntegrityError: An error occured when create_vouchers method returns
an IntegrityError exception
"""
"""
product_class
=
ProductClass
.
objects
.
get
(
slug
=
'coupon'
)
product_class
=
ProductClass
.
objects
.
get
(
slug
=
'coupon'
)
...
@@ -231,25 +238,21 @@ class CouponViewSet(EdxOrderPlacementMixin, viewsets.ModelViewSet):
...
@@ -231,25 +238,21 @@ class CouponViewSet(EdxOrderPlacementMixin, viewsets.ModelViewSet):
# Vouchers are created during order and not fulfillment like usual
# Vouchers are created during order and not fulfillment like usual
# because we want vouchers to be part of the line in the order.
# because we want vouchers to be part of the line in the order.
try
:
create_vouchers
(
create_vouchers
(
name
=
title
,
name
=
title
,
benefit_type
=
data
[
'benefit_type'
],
benefit_type
=
data
[
'benefit_type'
],
benefit_value
=
Decimal
(
data
[
'benefit_value'
]),
benefit_value
=
Decimal
(
data
[
'benefit_value'
]),
catalog
=
data
[
'catalog'
],
catalog
=
data
[
'catalog'
],
coupon
=
coupon_product
,
coupon
=
coupon_product
,
end_datetime
=
data
[
'end_date'
],
end_datetime
=
data
[
'end_date'
],
code
=
data
[
'code'
]
or
None
,
code
=
data
[
'code'
]
or
None
,
quantity
=
int
(
data
[
'quantity'
]),
quantity
=
int
(
data
[
'quantity'
]),
start_datetime
=
data
[
'start_date'
],
start_datetime
=
data
[
'start_date'
],
voucher_type
=
data
[
'voucher_type'
],
voucher_type
=
data
[
'voucher_type'
],
max_uses
=
data
[
'max_uses'
],
max_uses
=
data
[
'max_uses'
],
catalog_query
=
data
[
'catalog_query'
],
catalog_query
=
data
[
'catalog_query'
],
course_seat_types
=
data
[
'course_seat_types'
]
course_seat_types
=
data
[
'course_seat_types'
]
)
)
except
IntegrityError
:
logger
.
exception
(
'Failed to create vouchers for [
%
s] coupon.'
,
coupon_product
.
title
)
raise
coupon_vouchers
=
CouponVouchers
.
objects
.
get
(
coupon
=
coupon_product
)
coupon_vouchers
=
CouponVouchers
.
objects
.
get
(
coupon
=
coupon_product
)
...
...
ecommerce/static/js/models/coupon_model.js
View file @
e01699f3
...
@@ -92,9 +92,10 @@ define([
...
@@ -92,9 +92,10 @@ define([
}
}
},
},
code
:
{
code
:
{
pattern
:
/^
[
a-zA-Z0-9
]
+$/
,
required
:
false
,
required
:
false
,
rangeLength
:
[
8
,
16
],
rangeLength
:
[
1
,
16
],
msg
:
gettext
(
'
Code field must be empty or between 8 and 16 characters
'
)
msg
:
gettext
(
'
This field must be empty or contain 1-16 alphanumeric characters.
'
)
},
},
catalog_query
:
{
catalog_query
:
{
required
:
function
()
{
required
:
function
()
{
...
...
ecommerce/static/js/test/specs/models/coupon_model_spec.js
View file @
e01699f3
...
@@ -100,6 +100,16 @@ define([
...
@@ -100,6 +100,16 @@ define([
model
.
validate
();
model
.
validate
();
expect
(
model
.
isValid
()).
toBeTruthy
();
expect
(
model
.
isValid
()).
toBeTruthy
();
});
});
it
(
'should validate coupon code.'
,
function
()
{
model
.
set
(
'code'
,
'!#$%&/()='
);
model
.
validate
();
expect
(
model
.
isValid
()).
toBeFalsy
();
model
.
set
(
'code'
,
'CODE12345'
);
model
.
validate
();
expect
(
model
.
isValid
()).
toBeTruthy
();
});
});
});
describe
(
'test model methods'
,
function
()
{
describe
(
'test model methods'
,
function
()
{
...
...
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