Commit b2f21ef4 by Waheed Ahmed

Complete Order History tab for students on account settings page.

ECOM-2361
parent d19098ba
"""
Stub implementation of ecommerce service for acceptance tests
"""
import re
import urlparse
from .http import StubHttpRequestHandler, StubHttpService
class StubEcommerceServiceHandler(StubHttpRequestHandler): # pylint: disable=missing-docstring
def do_GET(self): # pylint: disable=invalid-name, missing-docstring
pattern_handlers = {
'/api/v2/orders/$': self.get_orders_list,
}
if self.match_pattern(pattern_handlers):
return
self.send_response(404, content='404 Not Found')
def match_pattern(self, pattern_handlers):
"""
Find the correct handler method given the path info from the HTTP request.
"""
path = urlparse.urlparse(self.path).path
for pattern in pattern_handlers:
match = re.match(pattern, path)
if match:
pattern_handlers[pattern](**match.groupdict())
return True
return None
def get_orders_list(self):
"""
Stubs the orders list endpoint.
"""
orders = {
'results': [
{
'status': 'Complete',
'number': 'Edx-123',
'total_excl_tax': '100.0',
'date_placed': '2016-04-21T23:14:23Z',
'lines': [
{
'title': 'Test Course',
'product': {
'attribute_values': [
{
'name': 'certificate_type',
'value': 'verified'
}
]
}
}
],
}
]
}
orders = self.server.config.get('orders', orders)
self.send_json_response(orders)
class StubEcommerceService(StubHttpService): # pylint: disable=missing-docstring
HANDLER_CLASS = StubEcommerceServiceHandler
......@@ -4,7 +4,9 @@ Command-line utility to start a stub service.
import sys
import time
import logging
from .comments import StubCommentsService
from .ecommerce import StubEcommerceService
from .xqueue import StubXQueueService
from .youtube import StubYouTubeService
from .lti import StubLtiService
......@@ -23,6 +25,7 @@ SERVICES = {
'video': VideoSourceHttpService,
'edxnotes': StubEdxNotesService,
'programs': StubProgramsService,
'ecommerce': StubEcommerceService,
}
# Log to stdout, including debug messages
......
......@@ -63,3 +63,19 @@ class AccountSettingsPage(FieldsMixin, PageObject):
Switch between the different account settings tabs.
"""
self.q(css='#{}'.format(tab_id)).click()
@property
def is_order_history_tab_visible(self):
""" Check if tab with the name "Order History" is visible."""
return self.q(css='.u-field-orderHistory').visible
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
def order_button_is_visible(self, field_id):
""" Check that if hovering over the order history row shows the
order detail link or not.
"""
return self.q(css='.u-field-{} .u-field-{}'.format(field_id, 'link')).visible
......@@ -444,6 +444,28 @@ class AccountSettingsPageTest(AccountSettingsTestMixin, WebAppTest):
self.assertEqual(self.account_settings_page.title_for_field(field_id), title)
self.assertEqual(self.account_settings_page.link_title_for_link_field(field_id), link_title)
def test_order_history(self):
"""
Test that we can see orders on Order History tab.
"""
# switch to "Order History" tab
self.account_settings_page.switch_account_settings_tabs('orders-tab')
# verify that we are on correct tab
self.assertTrue(self.account_settings_page.is_order_history_tab_visible)
expected_order_data = {
'title': 'Test Course',
'date': 'Date Placed:\nApr 21, 2016',
'price': 'Cost:\n$100.0',
'number': 'Order Number:\nEdx-123'
}
for field_name, value in expected_order_data.iteritems():
self.assertEqual(
self.account_settings_page.get_value_of_order_history_row_item('order-Edx-123', field_name), value
)
self.assertTrue(self.account_settings_page.order_button_is_visible('order-Edx-123'))
@attr('a11y')
class AccountSettingsA11yTest(AccountSettingsTestMixin, WebAppTest):
......
[
{
"pk": 2,
"model": "commerce.commerceconfiguration",
"fields": {
"enabled": 1,
"change_date": "2016-04-21 10:19:32.034856"
}
}
]
......@@ -189,6 +189,10 @@ INSTALLED_APPS += ('coursewarehistoryextended',)
BADGING_BACKEND = 'lms.djangoapps.badges.backends.tests.dummy_backend.DummyBackend'
# Configure the LMS to use our stub eCommerce implementation
ECOMMERCE_API_URL = 'http://localhost:8043/api/v2/'
ECOMMERCE_API_SIGNING_KEY = 'ecommerce-key'
#####################################################################
# Lastly, see if the developer has any local overrides.
try:
......
......@@ -52,7 +52,7 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers
var createAccountSettingsPage = function() {
var context = AccountSettingsPage(
FIELDS_DATA, AUTH_DATA, Helpers.USER_ACCOUNTS_API_URL, Helpers.USER_PREFERENCES_API_URL, 'edX'
FIELDS_DATA, [], AUTH_DATA, Helpers.USER_ACCOUNTS_API_URL, Helpers.USER_PREFERENCES_API_URL, 'edX'
);
return context.accountSettingsView;
};
......
......@@ -10,9 +10,18 @@
], function (gettext, $, _, Backbone, Logger, UserAccountModel, UserPreferencesModel,
AccountSettingsFieldViews, AccountSettingsView, StringUtils) {
return function (fieldsData, authData, userAccountsApiUrl, userPreferencesApiUrl, accountUserId, platformName) {
return function (
fieldsData,
ordersHistoryData,
authData,
userAccountsApiUrl,
userPreferencesApiUrl,
accountUserId,
platformName
) {
var accountSettingsElement, userAccountModel, userPreferencesModel, aboutSectionsData,
accountsSectionData, accountSettingsView, showAccountSettingsPage, showLoadingError;
accountsSectionData, ordersSectionData, accountSettingsView, showAccountSettingsPage,
showLoadingError, orderNumber;
accountSettingsElement = $('.wrapper-account-settings');
......@@ -170,13 +179,49 @@
}
];
ordersHistoryData.unshift(
{
'title': gettext('ORDER NAME'),
'order_date': gettext('ORDER PLACED'),
'price': gettext('TOTAL'),
'number': gettext('ORDER NUMBER')
}
);
ordersSectionData = [
{
title: gettext('My Orders'),
subtitle: StringUtils.interpolate(
gettext('This page contains information about orders that you have placed with {platform_name}.'), /* jshint ignore:line */
{platform_name: platformName}
),
fields: _.map(ordersHistoryData, function(order) {
orderNumber = order.number;
if (orderNumber === 'ORDER NUMBER') {
orderNumber = 'orderId';
}
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
})
};
})
}
];
accountSettingsView = new AccountSettingsView({
model: userAccountModel,
accountUserId: accountUserId,
el: accountSettingsElement,
tabSections: {
aboutTabSections: aboutSectionsData,
accountsTabSections: accountsSectionData
accountsTabSections: accountsSectionData,
ordersTabSections: ordersSectionData
},
userPreferencesModel: userPreferencesModel
});
......
......@@ -11,7 +11,9 @@
'text!templates/fields/field_link_account.underscore',
'text!templates/fields/field_dropdown_account.underscore',
'text!templates/fields/field_social_link_account.underscore',
'edx-ui-toolkit/js/utils/string-utils'
'text!templates/fields/field_order_history.underscore',
'edx-ui-toolkit/js/utils/string-utils',
'edx-ui-toolkit/js/utils/html-utils'
], function (
gettext, $, _, Backbone,
FieldViews,
......@@ -20,7 +22,9 @@
field_link_account_template,
field_dropdown_account_template,
field_social_link_template,
StringUtils
field_order_history_template,
StringUtils,
HtmlUtils
)
{
......@@ -224,6 +228,30 @@
return this.indicators.success + gettext('Successfully unlinked.');
}
}),
OrderHistoryFieldView: FieldViews.ReadonlyFieldView.extend({
fieldType: 'orderHistory',
fieldTemplate: field_order_history_template,
initialize: function (options) {
this.options = options;
this._super(options);
this.template = HtmlUtils.template(this.fieldTemplate);
},
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
}));
this.delegateEvents();
return this;
}
})
};
return AccountSettingsFieldViews;
......
......@@ -15,7 +15,8 @@
activeTab: 'aboutTabSections',
accountSettingsTabs: [
{name: 'aboutTabSections', id: 'about-tab', label: gettext('Account Information'), class: 'active'},
{name: 'accountsTabSections', id: 'accounts-tab', label: gettext('Linked Accounts')}
{name: 'accountsTabSections', id: 'accounts-tab', label: gettext('Linked Accounts')},
{name: 'ordersTabSections', id: 'orders-tab', label: gettext('Order History')}
],
events: {
'click .account-nav-link': 'changeTab'
......
......@@ -213,6 +213,7 @@ $dark-gray1: rgb(74,74,74);
$light-gray1: rgb(242,242,242);
$light-gray2: rgb(171,171,171);
$light-gray3: rgb(249,249,249);
$light-gray4: rgb(252,252,252);
$dark-gray2: rgb(151,151,151);
$blue1: rgb(74,144,226);
$blue2: rgb(0,161,229);
......
......@@ -193,6 +193,54 @@
}
}
.u-field-order {
display: flex;
align-items: center;
font-size: em(16);
color: $gray;
width: 100%;
padding-top: $baseline;
padding-bottom: $baseline;
line-height: normal;
span {
padding: $baseline;
}
.u-field-order-title {
@include float(left);
width: 26%;
font-size: em(20);
padding-left: ($baseline*2);
}
.u-field-order-value {
@include float(left);
width: 12%;
}
.u-field-order-date {
@include float(left);
width: 16%;
}
.u-field-order-link {
width: 15%;
padding: 0;
.u-field-link {
@extend %ui-clear-button;
@extend %btn-pl-default-base;
@include font-size(14);
border: 1px solid $blue;
color: $blue;
line-height: normal;
padding: 10px;
width: 110px;
}
}
}
.social-field-linked {
background: $m-gray-l4;
box-shadow: 0 1px 2px 1px $shadow-l2;
......@@ -267,6 +315,42 @@
}
}
.u-field-orderHistory {
border-bottom: none;
border: 1px solid $m-gray-l4;
margin-bottom: $baseline;
padding: 0;
&:last-child {
border-bottom: 1px solid $m-gray-l4;
}
&:hover, &:focus {
background-color: $light-gray4;
}
}
.u-field-order-orderId {
border: none;
margin-top: $baseline;
margin-bottom: 0;
padding-bottom: 0;
&:hover, &:focus {
background-color: transparent;
}
.u-field-order {
font-weight: $font-semibold;
padding-top: 0;
padding-bottom: 0;
.u-field-order-title {
font-size: em(16);
}
}
}
.u-field-social {
border-bottom: none;
margin-right: 20px;
......
<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-link">
<% if (receiptUrl) { %>
<a class="u-field-link" target="_blank" href="<%- receiptUrl %>"><%- gettext('Order Details') %><span class="sr"> for <%- orderId %></span></a>
<% } %>
</span>
</div>
......@@ -32,12 +32,14 @@ from openedx.core.djangolib.js_utils import dump_js_escaped_json, js_escaped_str
<%block name="js_extra">
<%static:require_module module_name="js/student_account/views/account_settings_factory" class_name="AccountSettingsFactory">
var fieldsData = ${ fields | n, dump_js_escaped_json };
var authData = ${ auth | n, dump_js_escaped_json };
var platformName = '${ static.get_platform_name() | n, js_escaped_string }';
var fieldsData = ${ fields | n, dump_js_escaped_json },
ordersHistoryData = ${ order_history | n, dump_js_escaped_json },
authData = ${ auth | n, dump_js_escaped_json },
platformName = '${ static.get_platform_name() | n, js_escaped_string }';
AccountSettingsFactory(
fieldsData,
ordersHistoryData,
authData,
'${ user_accounts_api_url | n, js_escaped_string }',
'${ user_preferences_api_url | n, js_escaped_string }',
......
<% _.each(sections, function(section) { %>
<div class="section">
<% if (section.subtitle) { %>
<p id="header-subtitle-<%- activeTabName %>" class="account-settings-header-subtitle"><%- gettext(section.subtitle) %></p>
<p id="header-subtitle-<%- activeTabName %>" class="account-settings-header-subtitle"><%- section.subtitle %></p>
<% } %>
<h3 class="section-header"><%- gettext(section.title) %></h3>
<div class="account-settings-section-body">
......
......@@ -106,6 +106,11 @@ class Env(object):
'programs': {
'port': 8090,
'log': BOK_CHOY_LOG_DIR / "bok_choy_programs.log",
},
'ecommerce': {
'port': 8043,
'log': BOK_CHOY_LOG_DIR / "bok_choy_ecommerce.log",
}
}
......
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