Files
edx-platform/lms/static/js/commerce/views/receipt_view.js

328 lines
11 KiB
JavaScript

/**
* View for the receipt page.
*/
var edx = edx || {};
(function ($, _, _s, Backbone) {
'use strict';
edx.commerce = edx.commerce || {};
edx.commerce.ReceiptView = Backbone.View.extend({
useEcommerceApi: true,
initialize: function () {
this.useEcommerceApi = !!($.url('?basket_id'));
_.bindAll(this, 'renderReceipt', 'renderError', 'getProviderData', 'renderProvider', 'getCourseData');
/* Mix non-conflicting functions from underscore.string (all but include, contains, and reverse) into
* the Underscore namespace.
*/
_.mixin(_s.exports());
this.render();
},
renderReceipt: function (data) {
var templateHtml = $("#receipt-tpl").html(),
context = {
platformName: this.$el.data('platform-name'),
verified: this.$el.data('verified').toLowerCase() === 'true'
},
providerId;
// Add the receipt info to the template context
this.courseKey = this.getOrderCourseKey(data)
this.username = this.$el.data('username');
_.extend(context, {
receipt: this.receiptContext(data),
courseKey: this.course_key
});
this.$el.html(_.template(templateHtml, context));
this.trackLinks();
this.getCourseData(this.courseKey).then(this.renderCourse, this.renderError)
providerId = this.getCreditProviderId(data);
if (providerId) {
this.getProviderData(providerId).then(this.renderProvider, this.renderError)
}
},
renderCourse: function(course) {
$(".course_name_placeholder").text(course.name);
},
renderProvider: function (context) {
var templateHtml = $("#provider-tpl").html(),
providerDiv = this.$el.find("#receipt-provider");
context.course_key = this.courseKey;
context.username = this.username;
providerDiv.html(_.template(templateHtml, context)).removeClass('hidden');
},
renderError: function () {
// Display an error
$('#error-container').removeClass('hidden');
},
render: function () {
var self = this,
orderId = $.url('?basket_id') || $.url('?payment-order-num');
if (orderId && this.$el.data('is-payment-complete')==='True') {
// Get the order details
self.$el.removeClass('hidden');
self.getReceiptData(orderId).then(self.renderReceipt, self.renderError);
} else {
self.renderError();
}
},
trackLinks: function () {
var $verifyNowButton = $('#verify_now_button'),
$verifyLaterButton = $('#verify_later_button');
// Track a virtual pageview, for easy funnel reconstruction.
window.analytics.page('payment', 'receipt');
// Track the user's decision to verify immediately
window.analytics.trackLink($verifyNowButton, 'edx.bi.user.verification.immediate', {
category: 'verification'
});
// Track the user's decision to defer their verification
window.analytics.trackLink($verifyLaterButton, 'edx.bi.user.verification.deferred', {
category: 'verification'
});
},
/**
* Retrieve receipt data from Oscar (via LMS).
* @param {int} basketId The basket that was purchased.
* @return {object} JQuery Promise.
*/
getReceiptData: function (basketId) {
var urlFormat = this.useEcommerceApi ? '/api/commerce/v0/baskets/%s/order/' : '/shoppingcart/receipt/%s/';
return $.ajax({
url: _.sprintf(urlFormat, basketId),
type: 'GET',
dataType: 'json'
}).retry({times: 5, timeout: 2000, statusCodes: [404]});
},
/**
* Retrieve credit provider data from LMS.
* @param {string} providerId The providerId of the credit provider.
* @return {object} JQuery Promise.
*/
getProviderData: function (providerId) {
var providerUrl = '/api/credit/v1/providers/%s/';
return $.ajax({
url: _.sprintf(providerUrl, providerId),
type: 'GET',
dataType: 'json'
}).retry({times: 5, timeout: 2000, statusCodes: [404]});
},
/**
* Retrieve course data from LMS.
* @param {string} courseId The courseId of the course.
* @return {object} JQuery Promise.
*/
getCourseData: function (courseId) {
var courseDetailUrl = '/api/course_structure/v0/courses/%s/';
return $.ajax({
url: _.sprintf(courseDetailUrl, courseId),
type: 'GET',
dataType: 'json'
}).retry({times: 5, timeout: 2000, statusCodes: [404]});
},
/**
* Construct the template context from data received
* from the E-Commerce API.
*
* @param {object} order Receipt data received from the server
* @return {object} Receipt template context.
*/
receiptContext: function (order) {
var self = this,
receiptContext;
if (this.useEcommerceApi) {
receiptContext = {
orderNum: order.number,
currency: order.currency,
purchasedDatetime: order.date_placed,
totalCost: self.formatMoney(order.total_excl_tax),
isRefunded: false,
items: [],
billedTo: null
};
if (order.billing_address){
receiptContext.billedTo = {
firstName: order.billing_address.first_name,
lastName: order.billing_address.last_name,
city: order.billing_address.city,
state: order.billing_address.state,
postalCode: order.billing_address.postcode,
country: order.billing_address.country
}
}
receiptContext.items = _.map(
order.lines,
function (line) {
return {
lineDescription: line.description,
cost: self.formatMoney(line.line_price_excl_tax)
};
}
);
} else {
receiptContext = {
orderNum: order.orderNum,
currency: order.currency,
purchasedDatetime: order.purchase_datetime,
totalCost: self.formatMoney(order.total_cost),
isRefunded: order.status === "refunded",
billedTo: {
firstName: order.billed_to.first_name,
lastName: order.billed_to.last_name,
city: order.billed_to.city,
state: order.billed_to.state,
postalCode: order.billed_to.postal_code,
country: order.billed_to.country
},
items: []
};
receiptContext.items = _.map(
order.items,
function (item) {
return {
lineDescription: item.line_desc,
cost: self.formatMoney(item.line_cost)
};
}
);
}
return receiptContext;
},
getOrderCourseKey: function (order) {
var length, items;
if (this.useEcommerceApi) {
length = order.lines.length;
for (var i = 0; i < length; i++) {
var line = order.lines[i],
attributeValues = _.find(line.product.attribute_values, function (attribute) {
return attribute.name === 'course_key'
});
// This method assumes that all items in the order are related to a single course.
if (attributeValues != undefined) {
return attributeValues['value'];
}
}
} else {
items = _.filter(order.items, function (item) {
return item.course_key;
});
if (items.length > 0) {
return items[0].course_key;
}
}
return null;
},
formatMoney: function (moneyStr) {
return Number(moneyStr).toFixed(2);
},
/**
* Check whether the payment is for the credit course or not.
*
* @param {object} order Receipt data received from the server
* @return {string} String of the provider_id or null.
*/
getCreditProviderId: function (order) {
var attributeValues,
line = order.lines[0];
if (this.useEcommerceApi) {
attributeValues = _.find(line.product.attribute_values, function (attribute) {
return attribute.name === 'credit_provider'
});
// This method assumes that all items in the order are related to a single course.
if (attributeValues != undefined) {
return attributeValues['value'];
}
}
return null;
},
});
new edx.commerce.ReceiptView({
el: $('#receipt-container')
});
})(jQuery, _, _.str, Backbone);
function completeOrder (event) {
var courseKey = $(event).data("course-key"),
username = $(event).data("username"),
providerId = $(event).data("provider"),
postData = {
'course_key': courseKey,
'username': username
},
errorContainer = $("#error-container");
analytics.track(
"edx.bi.credit.clicked_complete_credit",
{
category: "credit",
label: courseKey
}
);
$.ajax({
url: '/api/credit/v1/provider/' + providerId + '/request/',
type: 'POST',
headers: {
'X-CSRFToken': $.cookie('csrftoken')
},
data: JSON.stringify(postData) ,
context: this,
success: function(requestData){
var form = $('#complete-order-form');
$('input', form).remove();
form.attr( 'action', requestData.url );
form.attr( 'method', 'POST' );
_.each( requestData.parameters, function( value, key ) {
$('<input>').attr({
type: 'hidden',
name: key,
value: value
}).appendTo(form);
});
form.submit();
},
error: function(xhr){
errorContainer.removeClass("is-hidden");
errorContainer.removeClass("hidden");
}
});
}