diff --git a/lms/djangoapps/commerce/migrations/0005_auto_20160831_0247.py b/lms/djangoapps/commerce/migrations/0005_auto_20160831_0247.py new file mode 100644 index 0000000000..fd94a1d798 --- /dev/null +++ b/lms/djangoapps/commerce/migrations/0005_auto_20160831_0247.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('sites', '0001_initial'), + ('commerce', '0004_auto_20160531_0950'), + ] + + operations = [ + migrations.RemoveField( + model_name='commerceconfiguration', + name='receipt_page', + ), + migrations.AddField( + model_name='commerceconfiguration', + name='site', + field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, blank=True, to='sites.Site', null=True), + ), + ] diff --git a/lms/djangoapps/commerce/models.py b/lms/djangoapps/commerce/models.py index 586a69ade6..70c2f7b9ef 100644 --- a/lms/djangoapps/commerce/models.py +++ b/lms/djangoapps/commerce/models.py @@ -1,10 +1,15 @@ """ Commerce-related models. """ +from django.contrib.sites.models import Site from django.db import models from django.utils.translation import ugettext_lazy as _ from config_models.models import ConfigurationModel +from openedx.core.djangoapps.site_configuration.models import SiteConfiguration + +from logging import getLogger +logger = getLogger(__name__) # pylint: disable=invalid-name class CommerceConfiguration(ConfigurationModel): @@ -33,15 +38,41 @@ class CommerceConfiguration(ConfigurationModel): 'Specified in seconds. Enable caching by setting this to a value greater than 0.' ) ) - receipt_page = models.CharField( - max_length=255, - default='/commerce/checkout/receipt/?orderNum=', - help_text=_('Path to order receipt page.') + site = models.ForeignKey( + Site, + on_delete=models.SET_NULL, + blank=True, + null=True ) def __unicode__(self): return "Commerce configuration" + def get_receipt_page_url(self, order_number): + """ + Return absolute receipt page URL. + + Arguments: + order_number (str): Order number + + Returns: + Absolute receipt page URL, consisting of site domain and site receipt page. + """ + site = self.site + if site: + try: + return '{site_domain}{receipt_page_url}{order_number}'.format( + site_domain=site.domain, + receipt_page_url=site.configuration.receipt_page_url, # pylint: disable=no-member + order_number=order_number + ) + except AttributeError: + logger.info("Site Configuration is not enabled for site (%s).", site) + return '{default_receipt_page_url}{order_number}'.format( + default_receipt_page_url=SiteConfiguration.DEFAULT_RECEIPT_PAGE_URL, + order_number=order_number + ) + @property def is_cache_enabled(self): """Whether responses from the Ecommerce API will be cached.""" diff --git a/lms/djangoapps/commerce/tests/test_models.py b/lms/djangoapps/commerce/tests/test_models.py new file mode 100644 index 0000000000..8c593718da --- /dev/null +++ b/lms/djangoapps/commerce/tests/test_models.py @@ -0,0 +1,64 @@ +""" Tests for commerce models. """ + +import ddt + +from django.test import TestCase + +from commerce.models import CommerceConfiguration +from microsite_configuration.tests.factories import SiteFactory +from openedx.core.djangoapps.site_configuration.models import SiteConfiguration +from openedx.core.djangoapps.site_configuration.tests.factories import SiteConfigurationFactory + + +@ddt.ddt +class CommerceConfigurationModelTests(TestCase): + """ Tests for the CommerceConfiguration model. """ + + def setUp(self): + """ + Create CommerceConfiguration object + """ + super(CommerceConfigurationModelTests, self).setUp() + self.site = SiteFactory() + self.order_number = "TEST_ORDER_NUMBER" + + def configure_commerce(self, is_configured, is_default_page): + """ + Helper for creating specific Commerce Configuration. + + Arguments: + is_configured (bool): Indicates whether or not the Site has Site Configuration. + is_default_page (bool): Indicates whether or not the LMS receipt page is used + + Returns: + Commerce configuration. + """ + if not is_default_page: + if is_configured: + SiteConfigurationFactory.create( + site=self.site, + receipt_page_url='receipt/page/url', + ) + + return CommerceConfiguration.objects.create( + enabled=True, + site=self.site if not is_default_page else None + ) + + @ddt.data((True, False), (False, False), (False, True)) + @ddt.unpack + def test_get_receipt_page_url_site_configured(self, is_configured, is_default_page): + commerce_configuration = self.configure_commerce(is_configured, is_default_page) + receipt_page_url = commerce_configuration.get_receipt_page_url(self.order_number) + expected_receipt_page_url = '{site_domain}{receipt_page_url}{order_number}'.format( + site_domain=self.site.domain, + receipt_page_url=self.site.configuration.receipt_page_url, # pylint: disable=no-member + order_number=self.order_number + ) if (is_configured and not is_default_page) else '{default_receipt_page_url}{order_number}'.format( + default_receipt_page_url=SiteConfiguration.DEFAULT_RECEIPT_PAGE_URL, + order_number=self.order_number + ) + self.assertEqual( + receipt_page_url, + expected_receipt_page_url + ) diff --git a/lms/djangoapps/commerce/tests/test_views.py b/lms/djangoapps/commerce/tests/test_views.py index 8ef5a8cc40..b406c96c43 100644 --- a/lms/djangoapps/commerce/tests/test_views.py +++ b/lms/djangoapps/commerce/tests/test_views.py @@ -5,7 +5,6 @@ from nose.plugins.attrib import attr import ddt import json from django.core.urlresolvers import reverse -from django.test import TestCase import mock from student.tests.factories import UserFactory diff --git a/lms/djangoapps/student_account/views.py b/lms/djangoapps/student_account/views.py index ec8bdda333..55e680f8fb 100644 --- a/lms/djangoapps/student_account/views.py +++ b/lms/djangoapps/student_account/views.py @@ -347,7 +347,7 @@ def get_user_orders(user): 'order_date': strftime_localized( date_placed.replace(tzinfo=pytz.UTC), 'SHORT_DATE' ), - 'receipt_url': commerce_configuration.receipt_page + order['number'] + 'receipt_url': commerce_configuration.get_receipt_page_url(order['number']) } user_orders.append(order_data) except KeyError: diff --git a/openedx/core/djangoapps/site_configuration/migrations/0003_siteconfiguration_receipt_page_url.py b/openedx/core/djangoapps/site_configuration/migrations/0003_siteconfiguration_receipt_page_url.py new file mode 100644 index 0000000000..35eb9a8cda --- /dev/null +++ b/openedx/core/djangoapps/site_configuration/migrations/0003_siteconfiguration_receipt_page_url.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('site_configuration', '0002_auto_20160720_0231'), + ] + + operations = [ + migrations.AddField( + model_name='siteconfiguration', + name='receipt_page_url', + field=models.CharField(default=b'/commerce/checkout/receipt/?orderNum=', help_text='Path to order receipt page.', max_length=255), + ), + ] diff --git a/openedx/core/djangoapps/site_configuration/models.py b/openedx/core/djangoapps/site_configuration/models.py index 61c05eb044..e9c5d3a5ff 100644 --- a/openedx/core/djangoapps/site_configuration/models.py +++ b/openedx/core/djangoapps/site_configuration/models.py @@ -7,6 +7,7 @@ from django.db import models from django.contrib.sites.models import Site from django.db.models.signals import post_save from django.dispatch import receiver +from django.utils.translation import ugettext_lazy as _ from django_extensions.db.models import TimeStampedModel from jsonfield.fields import JSONField @@ -25,6 +26,8 @@ class SiteConfiguration(models.Model): site (OneToOneField): one to one field relating each configuration to a single site values (JSONField): json field to store configurations for a site """ + DEFAULT_RECEIPT_PAGE_URL = '/commerce/checkout/receipt/?orderNum=' + site = models.OneToOneField(Site, related_name='configuration') enabled = models.BooleanField(default=False, verbose_name="Enabled") values = JSONField( @@ -32,6 +35,11 @@ class SiteConfiguration(models.Model): blank=True, load_kwargs={'object_pairs_hook': collections.OrderedDict} ) + receipt_page_url = models.CharField( + max_length=255, + default=DEFAULT_RECEIPT_PAGE_URL, + help_text=_('Path to order receipt page.') + ) def __unicode__(self): return u"".format(site=self.site)