Skip to content

Commit bc15a5e

Browse files
authored
Merge pull request #33 from q-verse/develop
release-2020-06-03
2 parents 25dad78 + 0893648 commit bc15a5e

File tree

24 files changed

+193
-60
lines changed

24 files changed

+193
-60
lines changed

cms/envs/common.py

+5
Original file line numberDiff line numberDiff line change
@@ -1575,3 +1575,8 @@
15751575
# setting for the FileWrapper class used to iterate over the export file data.
15761576
# See: https://docs.python.org/2/library/wsgiref.html#wsgiref.util.FileWrapper
15771577
COURSE_EXPORT_DOWNLOAD_CHUNK_SIZE = 8192
1578+
1579+
############## Qverse Features #########################
1580+
1581+
# edX does not set the following variable in cms. But we have to set these, otherwise it gives an error.
1582+
PAID_COURSE_REGISTRATION_CURRENCY = ['usd', '$']

cms/envs/production.py

+6
Original file line numberDiff line numberDiff line change
@@ -624,3 +624,9 @@
624624
########################## Derive Any Derived Settings #######################
625625

626626
derive_settings(__name__)
627+
628+
############## Qverse Features #########################
629+
630+
# edX does not set the following variable in cms. But we have to set these, otherwise it gives an error.
631+
PAID_COURSE_REGISTRATION_CURRENCY = ENV_TOKENS.get('PAID_COURSE_REGISTRATION_CURRENCY',
632+
PAID_COURSE_REGISTRATION_CURRENCY)

common/djangoapps/course_modes/models.py

+8-7
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
'bulk_sku',
3434
])
3535

36+
CURRENCY = settings.PAID_COURSE_REGISTRATION_CURRENCY[0]
3637

3738
class CourseMode(models.Model):
3839
"""
@@ -70,14 +71,14 @@ def course_id(self, value):
7071
# The 'pretty' name that can be translated and displayed
7172
mode_display_name = models.CharField(max_length=255, verbose_name=_("Display Name"))
7273

73-
# The price in USD that we would like to charge for this mode of the course
74+
# The price in configured currency that we would like to charge for this mode of the course
7475
# Historical note: We used to allow users to choose from several prices, but later
7576
# switched to using a single price. Although this field is called `min_price`, it is
7677
# really just the price of the course.
7778
min_price = models.IntegerField(default=0, verbose_name=_("Price"))
7879

7980
# the currency these prices are in, using lower case ISO currency codes
80-
currency = models.CharField(default="usd", max_length=8)
81+
currency = models.CharField(default=CURRENCY, max_length=8)
8182

8283
# The datetime at which the course mode will expire.
8384
# This is used to implement "upgrade" deadlines.
@@ -181,7 +182,7 @@ def course_id(self, value):
181182
# "honor" to "audit", we still need to have the shoppingcart
182183
# use "honor"
183184
DEFAULT_SHOPPINGCART_MODE_SLUG = HONOR
184-
DEFAULT_SHOPPINGCART_MODE = Mode(HONOR, _('Honor'), 0, '', 'usd', None, None, None, None)
185+
DEFAULT_SHOPPINGCART_MODE = Mode(HONOR, _('Honor'), 0, '', CURRENCY, None, None, None, None)
185186

186187
CACHE_NAMESPACE = u"course_modes.CourseMode.cache."
187188

@@ -757,12 +758,12 @@ def get_course_prices(course, verified_only=False):
757758
if verified_only:
758759
registration_price = CourseMode.min_course_price_for_verified_for_currency(
759760
course.id,
760-
settings.PAID_COURSE_REGISTRATION_CURRENCY[0]
761+
CURRENCY
761762
)
762763
else:
763764
registration_price = CourseMode.min_course_price_for_currency(
764765
course.id,
765-
settings.PAID_COURSE_REGISTRATION_CURRENCY[0]
766+
CURRENCY
766767
)
767768

768769
if registration_price > 0:
@@ -813,15 +814,15 @@ class Meta(object):
813814
# The 'pretty' name that can be translated and displayed
814815
mode_display_name = models.CharField(max_length=255)
815816

816-
# minimum price in USD that we would like to charge for this mode of the course
817+
# minimum price in configued currency that we would like to charge for this mode of the course
817818
min_price = models.IntegerField(default=0)
818819

819820
# the suggested prices for this mode
820821
suggested_prices = models.CharField(max_length=255, blank=True, default='',
821822
validators=[validate_comma_separated_integer_list])
822823

823824
# the currency these prices are in, using lower case ISO currency codes
824-
currency = models.CharField(default="usd", max_length=8)
825+
currency = models.CharField(default=CURRENCY, max_length=8)
825826

826827
# turn this mode off after the given expiration date
827828
expiration_date = models.DateField(default=None, null=True, blank=True)

common/djangoapps/course_modes/views.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from __future__ import unicode_literals
12
"""
23
Views for the course_mode module
34
"""
@@ -8,6 +9,7 @@
89

910
import waffle
1011
from babel.dates import format_datetime
12+
from django.conf import settings
1113
from django.contrib.auth.decorators import login_required
1214
from django.db import transaction
1315
from django.http import HttpResponse, HttpResponseBadRequest
@@ -219,6 +221,7 @@ def get(self, request, course_id, error=None):
219221
if x.strip()
220222
]
221223
context["currency"] = verified_mode.currency.upper()
224+
context["currency_symbol"] = settings.PAID_COURSE_REGISTRATION_CURRENCY[1]
222225
context["min_price"] = verified_mode.min_price
223226
context["verified_name"] = verified_mode.name
224227
context["verified_description"] = verified_mode.description
@@ -355,7 +358,7 @@ def create_mode(request, course_id):
355358
`sku` (str): The product SKU value.
356359
357360
By default, this endpoint will create an 'honor' mode for the given course with display name
358-
'Honor Code', a minimum price of 0, no suggested prices, and using USD as the currency.
361+
'Honor Code', a minimum price of 0, no suggested prices, and using configured default currency as the currency.
359362
360363
Args:
361364
request (`Request`): The Django Request object.
@@ -369,7 +372,7 @@ def create_mode(request, course_id):
369372
'mode_display_name': u'Honor Code Certificate',
370373
'min_price': 0,
371374
'suggested_prices': u'',
372-
'currency': u'usd',
375+
'currency': unicode(settings.PAID_COURSE_REGISTRATION_CURRENCY[0]),
373376
'sku': None,
374377
}
375378

common/static/common/js/components/PortfolioExperimentUpsellModal.jsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ export class PortfolioExperimentUpsellModal extends React.Component {
4949
</div>
5050
);
5151

52+
let upgradeText = `Upgrade (${this.props.currency_symbol}100 ${this.props.currency})`;
53+
5254
return (
5355
<Modal
5456
open={this.state.isOpen}
@@ -58,8 +60,8 @@ export class PortfolioExperimentUpsellModal extends React.Component {
5860
body={body}
5961
buttons={[
6062
(<Button
61-
label={'Upgrade ($100 USD)'}
62-
display={'Upgrade ($100 USD)'}
63+
label={upgradeText}
64+
display={upgradeText}
6365
buttonType='success'
6466
// unfortunately, Button components don't have an href attribute
6567
onClick={() => {}}

common/static/common/js/components/UpsellExperimentModal.jsx

+4-3
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export class UpsellExperimentModal extends React.Component {
6565
</div>
6666
);
6767
const { buttonDestinationURL } = this.props;
68+
let upgradeText = `Upgrade (${this.props.currency_symbol}100 ${this.props.currency})`;
6869
return (
6970
<Modal
7071
open={this.state.isOpen}
@@ -74,8 +75,8 @@ export class UpsellExperimentModal extends React.Component {
7475
body={body}
7576
buttons={[
7677
(<Button
77-
label={"Upgrade ($100 USD)"}
78-
display={"Upgrade ($100 USD)"}
78+
label={upgradeText}
79+
display={upgradeText}
7980
buttonType="success"
8081
// unfortunately, Button components don't have an href component
8182
onClick={() => window.location = buttonDestinationURL}
@@ -88,4 +89,4 @@ export class UpsellExperimentModal extends React.Component {
8889

8990
UpsellExperimentModal.propTypes = {
9091
buttonDestinationURL: PropTypes.string.isRequired,
91-
};
92+
};

common/test/acceptance/pages/lms/create_mode.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def __init__(self, browser, course_id, mode_slug=None, mode_display_name=None, m
2020
"""The mode creation page is an endpoint for HTTP GET requests.
2121
2222
By default, it will create an 'honor' mode for the given course with display name
23-
'Honor Code', a minimum price of 0, no suggested prices, and using USD as the currency.
23+
'Honor Code', a minimum price of 0, no suggested prices, and using configured currency as the currency.
2424
2525
Arguments:
2626
browser (Browser): The browser instance.

lms/djangoapps/courseware/views/views.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,8 @@ def course_about(request, course_id):
866866
reviews_fragment_view = CourseReviewsModuleFragmentView().render_to_fragment(request, course=course)
867867

868868
context = {
869+
'currency': settings.PAID_COURSE_REGISTRATION_CURRENCY[0],
870+
'currency_symbol': settings.PAID_COURSE_REGISTRATION_CURRENCY[1],
869871
'course': course,
870872
'course_details': course_details,
871873
'staff_access': staff_access,
@@ -917,7 +919,11 @@ def program_marketing(request, program_uuid):
917919
skus = program.get('skus')
918920
ecommerce_service = EcommerceService()
919921

920-
context = {'program': program}
922+
context = {
923+
'program': program,
924+
'currency': settings.PAID_COURSE_REGISTRATION_CURRENCY[0],
925+
'currency_symbol': settings.PAID_COURSE_REGISTRATION_CURRENCY[1],
926+
}
921927

922928
if program.get('is_learner_eligible_for_one_click_purchase') and skus:
923929
context['buy_button_href'] = ecommerce_service.get_checkout_page_url(*skus, program_uuid=program_uuid)

lms/djangoapps/shoppingcart/models.py

+11-8
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090

9191
# we need a tuple to represent the primary key of various OrderItem subclasses
9292
OrderItemSubclassPK = namedtuple('OrderItemSubclassPK', ['cls', 'pk'])
93+
CURRENCY = settings.PAID_COURSE_REGISTRATION_CURRENCY[0]
9394

9495

9596
class OrderTypes(object):
@@ -115,7 +116,7 @@ class Meta(object):
115116
app_label = "shoppingcart"
116117

117118
user = models.ForeignKey(User, db_index=True, on_delete=models.CASCADE)
118-
currency = models.CharField(default="usd", max_length=8) # lower case ISO currency codes
119+
currency = models.CharField(default=CURRENCY, max_length=8) # lower case ISO currency codes
119120
status = models.CharField(max_length=32, default='cart', choices=ORDER_STATUSES)
120121
purchase_time = models.DateTimeField(null=True, blank=True)
121122
refunded_time = models.DateTimeField(null=True, blank=True)
@@ -654,7 +655,7 @@ class Meta(object):
654655
unit_cost = models.DecimalField(default=0.0, decimal_places=2, max_digits=30)
655656
list_price = models.DecimalField(decimal_places=2, max_digits=30, null=True)
656657
line_desc = models.CharField(default="Misc. Item", max_length=1024)
657-
currency = models.CharField(default="usd", max_length=8) # lower case ISO currency codes
658+
currency = models.CharField(default=CURRENCY, max_length=8) # lower case ISO currency codes
658659
fulfilled_time = models.DateTimeField(null=True, db_index=True)
659660
refund_requested_time = models.DateTimeField(null=True, db_index=True)
660661
service_fee = models.DecimalField(default=0.0, decimal_places=2, max_digits=30)
@@ -687,7 +688,7 @@ def add_to_order(cls, order, *args, **kwargs):
687688
# this is a validation step to verify that the currency of the item we
688689
# are adding is the same as the currency of the order we are adding it
689690
# to
690-
currency = kwargs.get('currency', 'usd')
691+
currency = kwargs.get('currency', CURRENCY)
691692
if order.currency != currency and order.orderitem_set.exists():
692693
raise InvalidCartItem(_("Trying to add a different currency into the cart"))
693694

@@ -1009,7 +1010,7 @@ class Meta(object):
10091010
)
10101011
)
10111012
currency = models.CharField(
1012-
default="usd",
1013+
default=CURRENCY,
10131014
max_length=8,
10141015
help_text=ugettext_lazy("Lower-case ISO currency codes")
10151016
)
@@ -1104,7 +1105,7 @@ class Meta(object):
11041105
help_text=ugettext_lazy("The price per item sold, including discounts.")
11051106
)
11061107
currency = models.CharField(
1107-
default="usd",
1108+
default=CURRENCY,
11081109
max_length=8,
11091110
help_text=ugettext_lazy("Lower-case ISO currency codes")
11101111
)
@@ -1921,7 +1922,7 @@ def refund_cert_callback(sender, course_enrollment=None, skip_refund=False, **kw
19211922

19221923
@classmethod
19231924
@transaction.atomic
1924-
def add_to_order(cls, order, course_id, cost, mode, currency='usd'):
1925+
def add_to_order(cls, order, course_id, cost, mode, currency=CURRENCY):
19251926
"""
19261927
Add a CertificateItem to an order
19271928
@@ -2059,7 +2060,9 @@ def verified_certificates_contributing_more_than_minimum(cls, course_id):
20592060
course_id=course_id,
20602061
mode='verified',
20612062
status='purchased',
2062-
unit_cost__gt=(CourseMode.min_course_price_for_verified_for_currency(course_id, 'usd')))).count()
2063+
unit_cost__gt=(
2064+
CourseMode.min_course_price_for_verified_for_currency(course_id, CURRENCY))
2065+
)).count()
20632066

20642067
def analytics_data(self):
20652068
"""Simple function used to construct analytics data for the OrderItem.
@@ -2113,7 +2116,7 @@ class Meta(object):
21132116

21142117
@classmethod
21152118
@transaction.atomic
2116-
def add_to_order(cls, order, donation_amount, course_id=None, currency='usd'):
2119+
def add_to_order(cls, order, donation_amount, course_id=None, currency=CURRENCY):
21172120
"""Add a donation to an order.
21182121
21192122
Args:

lms/djangoapps/shoppingcart/processors/CyberSource2.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ def _payment_accepted(order_id, auth_amount, currency, decision):
387387
return {
388388
'accepted': False,
389389
'amt_charged': 0,
390-
'currency': 'usd',
390+
'currency': settings.PAID_COURSE_REGISTRATION_CURRENCY[0],
391391
'order': order
392392
}
393393

lms/djangoapps/shoppingcart/reports.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from decimal import Decimal
44

55
import unicodecsv
6+
from django.conf import settings
67
from django.utils.translation import ugettext as _
78
from six import text_type
89

@@ -164,6 +165,7 @@ def rows(self):
164165
total_enrolled = counts['total']
165166
audit_enrolled = counts['audit']
166167
honor_enrolled = counts['honor']
168+
currency = settings.PAID_COURSE_REGISTRATION_CURRENCY[0]
167169

168170
if counts['verified'] == 0:
169171
verified_enrolled = 0
@@ -172,7 +174,7 @@ def rows(self):
172174
else:
173175
verified_enrolled = counts['verified']
174176
gross_rev = CertificateItem.verified_certificates_monetary_field_sum(course_id, 'purchased', 'unit_cost')
175-
gross_rev_over_min = gross_rev - (CourseMode.min_course_price_for_verified_for_currency(course_id, 'usd') * verified_enrolled)
177+
gross_rev_over_min = gross_rev - (CourseMode.min_course_price_for_verified_for_currency(course_id, currency) * verified_enrolled)
176178

177179
num_verified_over_the_minimum = CertificateItem.verified_certificates_contributing_more_than_minimum(course_id)
178180

lms/djangoapps/verify_student/views.py

+1
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,7 @@ def get(
411411

412412
# Render the top-level page
413413
context = {
414+
'currency_symbol': settings.PAID_COURSE_REGISTRATION_CURRENCY[1],
414415
'contribution_amount': contribution_amount,
415416
'course': course,
416417
'course_key': unicode(course_key),

lms/static/js/verify_student/pay_and_verify.js

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ var edx = edx || {};
6565
function(price) { return Boolean(price); }
6666
),
6767
currency: $el.data('course-mode-currency'),
68+
currencySymbol: $el.data('currency-symbol'),
6869
processors: $el.data('processors'),
6970
verificationDeadline: $el.data('verification-deadline'),
7071
courseModeSlug: $el.data('course-mode-slug'),

lms/templates/learner_dashboard/program_details_view.underscore

+3-3
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@
2727
<% if (discount_data.is_discounted) { %>
2828
<span class='list-price'>
2929
<%- StringUtils.interpolate(
30-
gettext('${listPrice}'), {listPrice: discount_data.total_incl_tax_excl_discounts.toFixed(2)}
30+
gettext('{currency_symbol}{listPrice}'), {currency_symbol: currency_symbol, listPrice: discount_data.total_incl_tax_excl_discounts.toFixed(2)}
3131
)
3232
%>
3333
</span>
3434
<% } %>
3535
<%- StringUtils.interpolate(
36-
gettext(' ${price} {currency} )'),
37-
{price: full_program_price.toFixed(2), currency: discount_data.currency}
36+
gettext(' {currency_symbol}{price} {currency} )'),
37+
{currency_symbol:currency_symbol, price: full_program_price.toFixed(2), currency: discount_data.currency}
3838
)
3939
%>
4040
</a>

0 commit comments

Comments
 (0)