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
3ce7d773
Commit
3ce7d773
authored
Jun 27, 2016
by
Vedran Karacic
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Omit unavailable seats in offer landing page.
parent
af166e02
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
83 additions
and
21 deletions
+83
-21
ecommerce/coupons/tests/mixins.py
+16
-15
ecommerce/coupons/tests/test_views.py
+10
-1
ecommerce/coupons/views.py
+3
-3
ecommerce/extensions/api/v2/tests/views/test_vouchers.py
+49
-1
ecommerce/extensions/api/v2/views/vouchers.py
+5
-1
No files found.
ecommerce/coupons/tests/mixins.py
View file @
3ce7d773
...
...
@@ -19,22 +19,23 @@ class CatalogPreviewMockMixin(object):
def
setUp
(
self
):
super
(
CatalogPreviewMockMixin
,
self
)
.
setUp
()
def
mock_dynamic_catalog_course_runs_api
(
self
,
course_run
=
None
,
query
=
None
):
def
mock_dynamic_catalog_course_runs_api
(
self
,
course_run
=
None
,
query
=
None
,
course_run_info
=
None
):
""" Helper function to register a dynamic course catalog API endpoint for the course run information. """
course_run_info
=
{
'count'
:
1
,
'results'
:
[{
'key'
:
course_run
.
id
,
'title'
:
course_run
.
name
,
'start'
:
'2016-05-01T00:00:00Z'
,
'image'
:
{
'src'
:
'path/to/the/course/image'
}
}]
if
course_run
else
[{
'key'
:
'test'
,
'title'
:
'Test course'
,
}],
}
if
not
course_run_info
:
course_run_info
=
{
'count'
:
1
,
'results'
:
[{
'key'
:
course_run
.
id
,
'title'
:
course_run
.
name
,
'start'
:
'2016-05-01T00:00:00Z'
,
'image'
:
{
'src'
:
'path/to/the/course/image'
}
}]
if
course_run
else
[{
'key'
:
'test'
,
'title'
:
'Test course'
,
}],
}
course_run_info_json
=
json
.
dumps
(
course_run_info
)
course_run_url
=
'{}course_runs/?q={}'
.
format
(
settings
.
COURSE_CATALOG_API_URL
,
...
...
ecommerce/coupons/tests/test_views.py
View file @
3ce7d773
...
...
@@ -64,7 +64,7 @@ class CouponAppViewTests(TestCase):
self
.
assertEqual
(
response
.
status_code
,
200
)
class
GetVoucherTests
(
TestCase
):
class
GetVoucherTests
(
CourseCatalogTestMixin
,
TestCase
):
def
test_get_voucher_and_products_from_code
(
self
):
""" Verify that get_voucher_and_products_from_code() returns products and voucher. """
original_voucher
,
original_product
=
prepare_voucher
(
code
=
COUPON_CODE
)
...
...
@@ -130,6 +130,15 @@ class GetVoucherTests(TestCase):
valid
,
__
=
voucher_is_valid
(
voucher
=
voucher
,
products
=
[
product
],
request
=
request
)
self
.
assertFalse
(
valid
)
def
test_omitting_unavailable_voucher
(
self
):
""" Verify if there are more than one product, that availability check is omitted. """
request
=
RequestFactory
()
.
request
()
voucher
,
product
=
prepare_voucher
(
code
=
COUPON_CODE
)
product
.
expires
=
pytz
.
utc
.
localize
(
datetime
.
datetime
.
min
)
__
,
seat
=
self
.
create_course_and_seat
()
valid
,
__
=
voucher_is_valid
(
voucher
=
voucher
,
products
=
[
product
,
seat
],
request
=
request
)
self
.
assertTrue
(
valid
)
def
assert_error_messages
(
self
,
voucher
,
product
,
user
,
error_msg
):
""" Assert the proper error message is returned. """
voucher
.
offers
.
first
()
.
record_usage
(
discount
=
{
'freq'
:
1
,
'discount'
:
1
})
...
...
ecommerce/coupons/views.py
View file @
3ce7d773
...
...
@@ -90,10 +90,10 @@ def voucher_is_valid(voucher, products, request):
voucher_msg
=
msg
.
replace
(
'voucher'
,
'coupon'
)
return
False
,
voucher_msg
for
product
in
products
:
purchase_info
=
request
.
strategy
.
fetch_for_product
(
product
)
if
len
(
products
)
==
1
:
purchase_info
=
request
.
strategy
.
fetch_for_product
(
product
s
[
0
]
)
if
not
purchase_info
.
availability
.
is_available_to_buy
:
return
False
,
_
(
'Product [{product}] not available for purchase.'
.
format
(
product
=
product
))
return
False
,
_
(
'Product [{product}] not available for purchase.'
.
format
(
product
=
product
s
[
0
]
))
# If the voucher's number of applications exceeds it's limit.
offer
=
voucher
.
offers
.
first
()
...
...
ecommerce/extensions/api/v2/tests/views/test_vouchers.py
View file @
3ce7d773
from
__future__
import
unicode_literals
import
datetime
import
json
import
mock
import
ddt
import
httpretty
import
pytz
from
django.core.urlresolvers
import
reverse
from
django.http
import
Http404
from
opaque_keys.edx.keys
import
CourseKey
...
...
@@ -22,6 +24,7 @@ from ecommerce.courses.models import Course
from
ecommerce.extensions.api
import
serializers
from
ecommerce.extensions.api.v2.views.vouchers
import
VoucherViewSet
from
ecommerce.extensions.catalogue.tests.mixins
import
CourseCatalogTestMixin
from
ecommerce.extensions.partner.strategy
import
DefaultStrategy
from
ecommerce.extensions.test.factories
import
prepare_voucher
from
ecommerce.tests.mixins
import
Catalog
,
LmsApiMockMixin
from
ecommerce.tests.testcases
import
TestCase
...
...
@@ -33,7 +36,7 @@ Range = get_model('offer', 'Range')
StockRecord
=
get_model
(
'partner'
,
'StockRecord'
)
class
VoucherViewSetTests
(
TestCase
):
class
VoucherViewSetTests
(
CatalogPreviewMockMixin
,
CourseCatalogTestMixin
,
TestCase
):
""" Tests for the VoucherViewSet view set. """
path
=
reverse
(
'api:v2:vouchers-list'
)
...
...
@@ -63,6 +66,50 @@ class VoucherViewSetTests(TestCase):
self
.
assertEqual
(
response_data
[
'count'
],
1
)
self
.
assertEqual
(
response_data
[
'results'
][
0
][
'code'
],
COUPON_CODE
)
# NOTE (VK): This unit test is added here because it results in a segmentation fault if
# added to the test class below.
@httpretty.activate
@mock_course_catalog_api_client
def
test_omitting_unavailable_seats
(
self
):
""" Verify an unavailable seat is omitted from offer page results. """
course1
,
seat1
=
self
.
create_course_and_seat
()
course2
,
seat2
=
self
.
create_course_and_seat
()
course_run_info
=
{
'count'
:
2
,
'results'
:
[{
'key'
:
course1
.
id
,
'title'
:
course1
.
name
,
'start'
:
'2016-05-01T00:00:00Z'
,
'image'
:
{
'src'
:
'path/to/the/course/image'
}
},
{
'key'
:
course2
.
id
,
'title'
:
course2
.
name
,
'start'
:
'2016-05-01T00:00:00Z'
,
'image'
:
{
'src'
:
'path/to/the/course/image'
}
}]
}
self
.
mock_dynamic_catalog_course_runs_api
(
query
=
'*:*'
,
course_run_info
=
course_run_info
)
new_range
,
__
=
Range
.
objects
.
get_or_create
(
catalog_query
=
'*:*'
)
new_range
.
add_product
(
seat1
)
new_range
.
add_product
(
seat2
)
voucher
,
__
=
prepare_voucher
(
_range
=
new_range
)
voucher
,
products
=
get_voucher_and_products_from_code
(
voucher
.
code
)
factory
=
APIRequestFactory
()
request
=
factory
.
get
(
'/?code={}&page_size=6'
.
format
(
voucher
.
code
))
request
.
site
=
self
.
site
request
.
strategy
=
DefaultStrategy
()
offers
=
VoucherViewSet
()
.
get_offers
(
products
=
products
,
request
=
request
,
voucher
=
voucher
)
self
.
assertEqual
(
len
(
offers
),
2
)
products
[
1
]
.
expires
=
pytz
.
utc
.
localize
(
datetime
.
datetime
.
min
)
offers
=
VoucherViewSet
()
.
get_offers
(
products
=
products
,
request
=
request
,
voucher
=
voucher
)
self
.
assertEqual
(
len
(
offers
),
1
)
@ddt.ddt
@httpretty.activate
...
...
@@ -86,6 +133,7 @@ class VoucherViewOffersEndpointTests(
factory
=
APIRequestFactory
()
request
=
factory
.
get
(
'/?code={}&page_size=6'
.
format
(
code
))
request
.
site
=
self
.
site
request
.
strategy
=
DefaultStrategy
()
return
request
@ddt.data
((
'COUPONCODE'
,),
(
'NOT_FOUND_CODE'
,))
...
...
ecommerce/extensions/api/v2/views/vouchers.py
View file @
3ce7d773
...
...
@@ -110,7 +110,6 @@ class VoucherViewSet(NonDestroyableModelViewSet):
benefit
=
voucher
.
offers
.
first
()
.
benefit
catalog_query
=
benefit
.
range
.
catalog_query
offers
=
[]
if
catalog_query
:
query_results
=
request
.
site
.
siteconfiguration
.
course_catalog_api_client
.
course_runs
.
get
(
q
=
catalog_query
,
...
...
@@ -124,6 +123,11 @@ class VoucherViewSet(NonDestroyableModelViewSet):
contains_verified_course
=
(
benefit
.
range
.
course_seat_types
==
'verified'
)
for
product
in
products
:
# Omit unavailable seats from the offer results so that one seat does not cause an
# error message for every seat in the query result.
if
not
request
.
strategy
.
fetch_for_product
(
product
)
.
availability
.
is_available_to_buy
:
logger
.
info
(
'
%
s is unavailable to buy. Omitting it from the results.'
,
product
)
continue
course_id
=
product
.
course_id
course_catalog_data
=
next
((
result
for
result
in
query_results
if
result
[
'key'
]
==
course_id
),
None
)
...
...
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