Commit 9ef91591 by Ivan Ivic Committed by GitHub

Merge pull request #14906 from edx/iivic/LEARNER-381

Update Order History page to reflect bundled purchase
parents 205f0723 b682c43d
......@@ -38,18 +38,14 @@ class StubEcommerceServiceHandler(StubHttpRequestHandler): # pylint: disable=mi
{
'status': 'Complete',
'number': 'Edx-123',
'total_excl_tax': '100.0',
'total_excl_tax': '100.00',
'date_placed': '2016-04-21T23:14:23Z',
'lines': [
{
'title': 'Test Course',
'line_price_excl_tax': '100.00',
'product': {
'attribute_values': [
{
'name': 'certificate_type',
'value': 'verified'
}
]
'product_class': 'Seat'
}
}
],
......
......@@ -72,7 +72,7 @@ class AccountSettingsPage(FieldsMixin, PageObject):
def get_value_of_order_history_row_item(self, field_id, field_name):
""" Return the text value of the provided order field name."""
query = self.q(css='.u-field-{} .u-field-order-{}'.format(field_id, field_name))
return query.text[0] if query.present else None
return query.text if query.present else None
def order_button_is_visible(self, field_id):
""" Check that if hovering over the order history row shows the
......
......@@ -489,15 +489,25 @@ class AccountSettingsPageTest(AccountSettingsTestMixin, AcceptanceTest):
# verify that we are on correct tab
self.assertTrue(self.account_settings_page.is_order_history_tab_visible)
expected_order_data = {
'title': 'Test Course',
expected_order_data_first_row = {
'number': 'Order Number:\nEdx-123',
'date': 'Date Placed:\nApr 21, 2016',
'price': 'Cost:\n$100.0',
'number': 'Order Number:\nEdx-123'
'price': 'Cost:\n$100.00',
}
for field_name, value in expected_order_data.iteritems():
expected_order_data_second_row = {
'number': 'Product Name:\nTest Course',
'date': 'Date Placed:\nApr 21, 2016',
'price': 'Cost:\n$100.00',
}
for field_name, value in expected_order_data_first_row.iteritems():
self.assertEqual(
self.account_settings_page.get_value_of_order_history_row_item('order-Edx-123', field_name)[0], value
)
for field_name, value in expected_order_data_second_row.iteritems():
self.assertEqual(
self.account_settings_page.get_value_of_order_history_row_item('order-Edx-123', field_name), value
self.account_settings_page.get_value_of_order_history_row_item('order-Edx-123', field_name)[1], value
)
self.assertTrue(self.account_settings_page.order_button_is_visible('order-Edx-123'))
......
......@@ -164,6 +164,22 @@ class mock_get_orders(mock_ecommerce_api_endpoint):
)])
)
]
),
factories.OrderFactory(
lines=[
factories.OrderLineFactory(
product=factories.ProductFactory(attribute_values=[factories.ProductAttributeFactory(
name='certificate_type',
value='verified'
)])
),
factories.OrderLineFactory(
product=factories.ProductFactory(attribute_values=[factories.ProductAttributeFactory(
name='certificate_type',
value='verified'
)])
),
]
)
]
}
......
......@@ -39,11 +39,10 @@ class EcommerceService(object):
Receipt page for the specified Order.
"""
ecommerce_receipt_page_url = configuration_helpers.get_value('ECOMMERCE_RECEIPT_PAGE_URL')
if ecommerce_receipt_page_url:
receipt_page_url = self.get_absolute_ecommerce_url(ecommerce_receipt_page_url)
else:
receipt_page_url = self.config.receipt_page
return receipt_page_url + order_number
return self.get_absolute_ecommerce_url(ecommerce_receipt_page_url + order_number)
return self.config.receipt_page + order_number
def is_enabled(self, user):
"""
......
......@@ -634,20 +634,21 @@ class AccountSettingsViewTest(ThirdPartyAuthTestMixin, TestCase, ProgramsApiConf
self.assertContains(response, '<li class="item nav-global-01">')
def test_commerce_order_detail(self):
"""
Verify that get_user_orders returns the correct order data.
"""
with mock_get_orders():
order_detail = get_user_orders(self.user)
user_order = mock_get_orders.default_response['results'][0]
expected = [
{
'number': user_order['number'],
'price': user_order['total_excl_tax'],
'title': user_order['lines'][0]['title'],
for i, order in enumerate(mock_get_orders.default_response['results']):
expected = {
'number': order['number'],
'price': order['total_excl_tax'],
'order_date': 'Jan 01, 2016',
'receipt_url': '/commerce/checkout/receipt/?orderNum=' + user_order['number']
'receipt_url': '/commerce/checkout/receipt/?orderNum=' + order['number'],
'lines': order['lines'],
}
]
self.assertEqual(order_detail, expected)
self.assertEqual(order_detail[i], expected)
def test_commerce_order_detail_exception(self):
with mock_get_orders(exception=exceptions.HttpNotFoundError):
......@@ -673,15 +674,18 @@ class AccountSettingsViewTest(ThirdPartyAuthTestMixin, TestCase, ProgramsApiConf
self.assertEqual(order_detail, [])
def test_honor_course_order_detail(self):
def test_order_history_with_no_product(self):
response = {
'results': [
factories.OrderFactory(
lines=[
factories.OrderLineFactory(
product=None
),
factories.OrderLineFactory(
product=factories.ProductFactory(attribute_values=[factories.ProductAttributeFactory(
name='certificate_type',
value='honor'
value='verified'
)])
)
]
......@@ -691,22 +695,17 @@ class AccountSettingsViewTest(ThirdPartyAuthTestMixin, TestCase, ProgramsApiConf
with mock_get_orders(response=response):
order_detail = get_user_orders(self.user)
self.assertEqual(order_detail, [])
self.assertEqual(len(order_detail), 1)
def test_order_history_with_no_product(self):
def test_order_history_with_coupon(self):
"""
Verify that get_order_details returns empty receipt_url for coupon product.
"""
response = {
'results': [
factories.OrderFactory(
lines=[
factories.OrderLineFactory(
product=None
),
factories.OrderLineFactory(
product=factories.ProductFactory(attribute_values=[factories.ProductAttributeFactory(
name='certificate_type',
value='verified'
)])
)
factories.OrderLineFactory(product=factories.ProductFactory(product_class='Coupon'))
]
)
]
......@@ -714,7 +713,7 @@ class AccountSettingsViewTest(ThirdPartyAuthTestMixin, TestCase, ProgramsApiConf
with mock_get_orders(response=response):
order_detail = get_user_orders(self.user)
self.assertEqual(len(order_detail), 1)
self.assertEqual(order_detail[0]['receipt_url'], '')
@override_settings(SITE_NAME=settings.MICROSITE_LOGISTRATION_HOSTNAME)
......
......@@ -331,7 +331,6 @@ def get_user_orders(user):
"""
no_data = []
user_orders = []
allowed_course_modes = ['professional', 'verified', 'credit']
commerce_configuration = CommerceConfiguration.current()
user_query = {'username': user.username}
......@@ -344,26 +343,25 @@ def get_user_orders(user):
for order in commerce_user_orders:
if order['status'].lower() == 'complete':
for line in order['lines']:
product = line.get('product')
if product:
for attribute in product['attribute_values']:
if attribute['name'] == 'certificate_type' and attribute['value'] in allowed_course_modes:
try:
date_placed = datetime.strptime(order['date_placed'], "%Y-%m-%dT%H:%M:%SZ")
order_data = {
'number': order['number'],
'price': order['total_excl_tax'],
'title': order['lines'][0]['title'],
'order_date': strftime_localized(
date_placed.replace(tzinfo=pytz.UTC), 'SHORT_DATE'
),
'receipt_url': EcommerceService().get_receipt_page_url(order['number'])
}
user_orders.append(order_data)
except KeyError:
log.exception('Invalid order structure: %r', order)
return no_data
date_placed = datetime.strptime(order['date_placed'], "%Y-%m-%dT%H:%M:%SZ")
order_data = {
'number': order['number'],
'price': order['total_excl_tax'],
'order_date': strftime_localized(date_placed, 'SHORT_DATE'),
'receipt_url': EcommerceService().get_receipt_page_url(order['number']),
'lines': order['lines'],
}
# If the order lines contain a product that is not a Seat
# we do not want to display the Order Details button. It
# will break the receipt page if used.
for order_line in order['lines']:
product = order_line.get('product')
if product and product.get('product_class') != 'Seat':
order_data['receipt_url'] = ''
break
user_orders.append(order_data)
return user_orders
......
......@@ -229,12 +229,12 @@
}
return {
'view': new AccountSettingsFieldViews.OrderHistoryFieldView({
title: order.title,
totalPrice: order.price,
orderId: order.number,
orderDate: order.order_date,
receiptUrl: order.receipt_url,
valueAttribute: 'order-' + orderNumber
valueAttribute: 'order-' + orderNumber,
lines: order.lines
})
};
})
......
......@@ -325,12 +325,12 @@
render: function() {
HtmlUtils.setHtml(this.$el, this.template({
title: this.options.title,
totalPrice: this.options.totalPrice,
orderId: this.options.orderId,
orderDate: this.options.orderDate,
receiptUrl: this.options.receiptUrl,
valueAttribute: this.options.valueAttribute
valueAttribute: this.options.valueAttribute,
lines: this.options.lines
}));
this.delegateEvents();
return this;
......
......@@ -193,35 +193,37 @@
display: flex;
align-items: center;
font-size: em(16);
color: $gray;
font-weight: 600;
color: $dark-gray;
width: 100%;
padding-top: $baseline;
padding-bottom: $baseline;
line-height: normal;
flex-direction: row;
flex-wrap: wrap;
span {
padding: $baseline;
}
.u-field-order-title {
.u-field-order-number {
@include float(left);
width: 26%;
font-size: em(20);
padding-left: ($baseline*2);
width: 30%;
}
.u-field-order-value {
.u-field-order-date {
@include float(left);
width: 12%;
padding-left: 30px;
width: 20%;
}
.u-field-order-date {
.u-field-order-price {
@include float(left);
width: 16%;
width: 15%;
}
.u-field-order-link {
width: 15%;
width: 10%;
padding: 0;
.u-field-link {
......@@ -237,6 +239,16 @@
}
}
.u-field-order-lines {
@extend .u-field-order;
padding: 5px 0 0;
font-weight: 100;
.u-field-order-number {
padding: 20px 10px 20px 30px;
}
}
.social-field-linked {
background: $m-gray-l4;
box-shadow: 0 1px 2px 1px $shadow-l2;
......@@ -290,7 +302,7 @@
font-weight: $font-semibold;
}
}
.u-field-message {
position: relative;
padding: 24px 0 0 ($baseline*5);
......
<div class="field u-field-order" <% if (receiptUrl) { %> role="group" aria-labelledby="order-title-<%- orderId %>" <% } else { %> aria-hidden="true" <% } %>>
<span class="u-field-order-title" <% if (receiptUrl) { %> id="order-title-<%- orderId %>" <% } %>><%- title %></span>
<span class="u-field-order-date"><span class="sr">Date Placed: </span><%- orderDate %></span>
<span class="u-field-order-value u-field-order-price"><span class="sr">Cost: </span><% if (!isNaN(parseFloat(totalPrice))) { %>$<% } %><%- totalPrice %></span>
<span class="u-field-order-value u-field-order-number"><span class="sr">Order Number: </span><%- orderId %></span>
<span class="u-field-order-number"><span class="sr"><%- gettext('Order Number') %>: </span><%- orderId %></span>
<span class="u-field-order-date"><span class="sr"><%- gettext('Date Placed') %>: </span><%- orderDate %></span>
<span class="u-field-order-price"><span class="sr"><%- gettext('Cost') %>: </span><% if (!isNaN(parseFloat(totalPrice))) { %>$<% } %><%- totalPrice %></span>
<span class="u-field-order-link">
<% if (receiptUrl) { %>
<a class="u-field-link" target="_blank" href="<%- receiptUrl %>"><%- gettext('Order Details') %><span class="sr"> for <%- orderId %></span></a>
<a class="u-field-link" target="_blank" href="<%- receiptUrl %>"><%- gettext('Order Details') %><span class="sr"> <%- gettext('for') %> <%- orderId %></span></a>
<% } %>
</span>
<% _.each(lines, function(item){ %>
<div class="field u-field-order-lines">
<span class="u-field-order-number"><span class="sr"><%- gettext('Product Name') %>: </span><%- item.title %></span>
<span class="u-field-order-date"><span class="sr"><%- gettext('Date Placed') %>: </span><%- orderDate %></span>
<span class="u-field-order-price"><span class="sr"><%- gettext('Cost') %>: </span><% if (!isNaN(parseFloat(item.line_price_excl_tax))) { %>$<% } %><%- item.line_price_excl_tax %></span>
</div>
<% }); %>
</div>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment