Implement local currency in lms

LEARNER-2412
This commit is contained in:
Matthew Piatetsky
2017-09-29 15:47:26 -04:00
parent 344e13b1ce
commit c741bcbee7
11 changed files with 209 additions and 2 deletions

View File

@@ -16,6 +16,7 @@ from openedx.core.djangoapps.catalog.tests.mixins import CatalogIntegrationMixin
from openedx.core.djangoapps.catalog.utils import (
get_course_runs,
get_course_run_details,
get_currency_data,
get_program_types,
get_programs,
get_programs_with_type
@@ -237,6 +238,29 @@ class TestGetProgramTypes(CatalogIntegrationMixin, TestCase):
self.assertEqual(data, program)
@mock.patch(UTILS_MODULE + '.get_edx_api_data')
class TestGetCurrency(CatalogIntegrationMixin, TestCase):
"""Tests covering retrieval of currency data from the catalog service."""
@override_settings(COURSE_CATALOG_API_URL='https://api.example.com/v1/')
def test_get_currency_data(self, mock_get_edx_api_data):
"""Verify get_currency_data returns the currency data."""
currency_data = {
"code": "CAD",
"rate": 1.257237,
"symbol": "$"
}
mock_get_edx_api_data.return_value = currency_data
# Catalog integration is disabled.
data = get_currency_data()
self.assertEqual(data, [])
catalog_integration = self.create_catalog_integration()
UserFactory(username=catalog_integration.service_username)
data = get_currency_data()
self.assertEqual(data, currency_data)
@skip_unless_lms
@mock.patch(UTILS_MODULE + '.get_edx_api_data')
class TestGetCourseRuns(CatalogIntegrationMixin, TestCase):

View File

@@ -119,6 +119,29 @@ def get_program_types(name=None):
return []
def get_currency_data():
"""Retrieve currency data from the catalog service.
Returns:
list of dict, representing program types.
dict, if a specific program type is requested.
"""
catalog_integration = CatalogIntegration.current()
if catalog_integration.enabled:
try:
user = catalog_integration.get_service_user()
except ObjectDoesNotExist:
return []
api = create_catalog_api_client(user)
cache_key = '{base}.currency'.format(base=catalog_integration.CACHE_KEY)
return get_edx_api_data(catalog_integration, 'currency', api=api,
cache_key=cache_key if catalog_integration.is_cache_enabled else None)
else:
return []
def get_programs_with_type(site, include_hidden=True):
"""
Return the list of programs. You can filter the types of programs returned by using the optional

View File

@@ -0,0 +1,2 @@
<div id="currency_data" value='{"CAN": {"rate": 2.2, "code": "CAD", "symbol": "$"}}'></div>
<input type="submit" name="verified_mode" value="Pursue a Verified Certificate ($100 USD)">

View File

@@ -0,0 +1,78 @@
import whichCountry from 'which-country';
import 'jquery.cookie';
import $ from 'jquery'; // eslint-disable-line import/extensions
export class Currency { // eslint-disable-line import/prefer-default-export
setCookie(countryCode, l10nData) {
function pick(curr, arr) {
const obj = {};
arr.forEach((key) => {
obj[key] = curr[key];
});
return obj;
}
const userCountryData = pick(l10nData, [countryCode]);
let countryL10nData = userCountryData[countryCode];
if (countryL10nData) {
countryL10nData.countryCode = countryCode;
} else {
countryL10nData = {
countryCode: 'USA',
symbol: '$',
rate: '1',
code: 'USD',
};
}
this.countryL10nData = countryL10nData;
$.cookie('edx-price-l10n', JSON.stringify(countryL10nData), {
expires: 1,
});
}
setPrice() {
const l10nCookie = this.countryL10nData;
const lmsregex = /(\$)(\d*)( USD)/g;
const price = $('input[name="verified_mode"]').filter(':visible')[0];
const regexMatch = lmsregex.exec(price.value);
const dollars = parseFloat(regexMatch[2]);
const converted = dollars * l10nCookie.rate;
const string = `${l10nCookie.symbol}${Math.round(converted)} ${l10nCookie.code}`;
// Use regex to change displayed price on track selection
// based on edx-price-l10n cookie currency_data
price.value = price.value.replace(regexMatch[0], string);
}
getL10nData(countryCode) {
const l10nData = JSON.parse($('#currency_data').attr('value'));
if (l10nData) {
this.setCookie(countryCode, l10nData);
}
}
getCountry(position) {
const countryCode = whichCountry([position.coords.longitude, position.coords.latitude]);
this.countryL10nData = JSON.parse($.cookie('edx-price-l10n'));
if (countryCode) {
if (!(this.countryL10nData && this.countryL10nData.countryCode === countryCode)) {
// If pricing cookie has not been set or the country is not correct
// Make API call and set the cookie
this.getL10nData(countryCode);
}
}
this.setPrice();
}
getUserLocation() {
// Get user location from browser
navigator.geolocation.getCurrentPosition(this.getCountry.bind(this));
}
constructor(skipInitialize) {
if (!skipInitialize) {
this.getUserLocation();
}
}
}

View File

@@ -0,0 +1,64 @@
/* globals loadFixtures */
import $ from 'jquery'; // eslint-disable-line import/extensions
import { Currency } from '../currency';
describe('Currency factory', () => {
let currency;
let canadaPosition;
let usaPosition;
let japanPosition;
beforeEach(() => {
loadFixtures('course_experience/fixtures/course-currency-fragment.html');
currency = new Currency(true);
canadaPosition = {
coords: {
latitude: 58.773884,
longitude: -124.882581,
},
};
usaPosition = {
coords: {
latitude: 42.366202,
longitude: -71.973095,
},
};
japanPosition = {
coords: {
latitude: 35.857826,
longitude: 137.737495,
},
};
$.cookie('edx-price-l10n', null, { path: '/' });
});
describe('converts price to local currency', () => {
it('when location is US', () => {
currency.getCountry(usaPosition);
expect($('input[name="verified_mode"]').filter(':visible')[0].value).toEqual('Pursue a Verified Certificate ($100 USD)');
});
it('when location is an unsupported country', () => {
currency.getCountry(japanPosition);
expect($('input[name="verified_mode"]').filter(':visible')[0].value).toEqual('Pursue a Verified Certificate ($100 USD)');
});
it('when cookie is not set and country is supported', () => {
currency.getCountry(canadaPosition);
expect($('input[name="verified_mode"]').filter(':visible')[0].value).toEqual('Pursue a Verified Certificate ($220 CAD)');
});
it('when cookie is set to same country', () => {
currency.getCountry(canadaPosition);
$.cookie('edx-price-l10n', '{"rate":2.2,"code":"CAD","symbol":"$","countryCode":"CAN"}', { expires: 1 });
expect($('input[name="verified_mode"]').filter(':visible')[0].value).toEqual('Pursue a Verified Certificate ($220 CAD)');
});
it('when cookie is set to different country', () => {
currency.getCountry(canadaPosition);
$.cookie('edx-price-l10n', '{"rate":1,"code":"USD","symbol":"$","countryCode":"USA"}', { expires: 1 });
expect($('input[name="verified_mode"]').filter(':visible')[0].value).toEqual('Pursue a Verified Certificate ($220 CAD)');
});
});
});