diff --git a/lms/djangoapps/shoppingcart/models.py b/lms/djangoapps/shoppingcart/models.py index 506b50229f..92da04594c 100644 --- a/lms/djangoapps/shoppingcart/models.py +++ b/lms/djangoapps/shoppingcart/models.py @@ -21,7 +21,7 @@ from statsd import statsd from xmodule.modulestore.django import modulestore from xmodule.course_module import CourseDescriptor -from .exceptions import InvalidCartItem, PaymentException, PurchasedCallbackException +from .exceptions import InvalidCartItem, PurchasedCallbackException log = logging.getLogger("shoppingcart") @@ -201,11 +201,19 @@ class OrderItem(models.Model): @property def single_item_receipt_template(self): """ - the template that should be used when there's - only one item in the order + The template that should be used when there's only one item in the order """ return'shoppingcart/receipt.html' + @property + def additional_instruction_text(self): + """ + Individual instructions for this order item. + + Currently, only used for e-mails. + """ + return '' + class PaidCourseRegistration(OrderItem): """ @@ -322,6 +330,13 @@ class CertificateItem(OrderItem): course_enrollment = CourseEnrollment.objects.get(user=order.user, course_id=course_id) except ObjectDoesNotExist: course_enrollment = CourseEnrollment.create_enrollment(order.user, course_id, mode=mode) + + # do some validation on the enrollment mode + valid_modes = CourseMode.modes_for_course_dict(course_id) + if mode in valid_modes: + mode_info = valid_modes[mode] + else: + raise InvalidCartItem(_("Mode {mode} does not exist for {course_id}").format(mode=mode, course_id=course_id)) item, _created = cls.objects.get_or_create( order=order, user=order.user, @@ -332,8 +347,8 @@ class CertificateItem(OrderItem): item.status = order.status item.qty = 1 item.unit_cost = cost - item.line_desc = _("{mode} certificate for course {course_id}").format(mode=item.mode, - course_id=course_id) + item.line_desc = _("Certificate of Achievement, {mode_name} for course {course_id}").format(mode_name=mode_info.name, + course_id=course_id) item.currency = currency order.currency = currency order.save() @@ -354,3 +369,9 @@ class CertificateItem(OrderItem): return 'shoppingcart/verified_cert_receipt.html' else: return super(CertificateItem, self).single_item_receipt_template + + @property + def additional_instruction_text(self): + return _("Note - you have up to 2 weeks into the course to unenroll from the Verified Certificate option \ + and receive a full refund. To receive your refund, contact {billing_email}.").format( + billing_email=settings.PAYMENT_SUPPORT_EMAIL) diff --git a/lms/djangoapps/shoppingcart/tests/test_models.py b/lms/djangoapps/shoppingcart/tests/test_models.py index ef1674e8b9..ccd4390d57 100644 --- a/lms/djangoapps/shoppingcart/tests/test_models.py +++ b/lms/djangoapps/shoppingcart/tests/test_models.py @@ -30,28 +30,28 @@ class OrderTest(TestCase): # create a cart cart = Order.get_cart_for_user(user=self.user) # add something to it - CertificateItem.add_to_order(cart, self.course_id, self.cost, 'verified') + CertificateItem.add_to_order(cart, self.course_id, self.cost, 'honor') # should return the same cart cart2 = Order.get_cart_for_user(user=self.user) self.assertEquals(cart2.orderitem_set.count(), 1) def test_cart_clear(self): cart = Order.get_cart_for_user(user=self.user) - CertificateItem.add_to_order(cart, self.course_id, self.cost, 'verified') - CertificateItem.add_to_order(cart, 'test/course1', self.cost, 'verified') + CertificateItem.add_to_order(cart, self.course_id, self.cost, 'honor') + CertificateItem.add_to_order(cart, 'test/course1', self.cost, 'honor') self.assertEquals(cart.orderitem_set.count(), 2) cart.clear() self.assertEquals(cart.orderitem_set.count(), 0) def test_add_item_to_cart_currency_match(self): cart = Order.get_cart_for_user(user=self.user) - CertificateItem.add_to_order(cart, self.course_id, self.cost, 'verified', currency='eur') + CertificateItem.add_to_order(cart, self.course_id, self.cost, 'honor', currency='eur') # verify that a new item has been added self.assertEquals(cart.orderitem_set.count(), 1) # verify that the cart's currency was updated self.assertEquals(cart.currency, 'eur') with self.assertRaises(InvalidCartItem): - CertificateItem.add_to_order(cart, self.course_id, self.cost, 'verified', currency='usd') + CertificateItem.add_to_order(cart, self.course_id, self.cost, 'honor', currency='usd') # assert that this item did not get added to the cart self.assertEquals(cart.orderitem_set.count(), 1) @@ -63,7 +63,7 @@ class OrderTest(TestCase): ('test/course3', 10), ('test/course4', 20)] for course, cost in course_costs: - CertificateItem.add_to_order(cart, course, cost, 'verified') + CertificateItem.add_to_order(cart, course, cost, 'honor') self.assertEquals(cart.orderitem_set.count(), len(course_costs)) self.assertEquals(cart.total_cost, sum(cost for _course, cost in course_costs)) @@ -73,7 +73,7 @@ class OrderTest(TestCase): # CertificateItem, which is not quite good unit test form. Sorry. cart = Order.get_cart_for_user(user=self.user) self.assertFalse(CourseEnrollment.is_enrolled(self.user, self.course_id)) - CertificateItem.add_to_order(cart, self.course_id, self.cost, 'verified') + item = CertificateItem.add_to_order(cart, self.course_id, self.cost, 'honor') # course enrollment object should be created but still inactive self.assertFalse(CourseEnrollment.is_enrolled(self.user, self.course_id)) cart.purchase() @@ -84,12 +84,13 @@ class OrderTest(TestCase): self.assertEquals('Order Payment Confirmation', mail.outbox[0].subject) self.assertIn(settings.PAYMENT_SUPPORT_EMAIL, mail.outbox[0].body) self.assertIn(unicode(cart.total_cost), mail.outbox[0].body) + self.assertIn(item.additional_instruction_text, mail.outbox[0].body) def test_purchase_item_failure(self): # once again, we're testing against the specific implementation of # CertificateItem cart = Order.get_cart_for_user(user=self.user) - CertificateItem.add_to_order(cart, self.course_id, self.cost, 'verified') + CertificateItem.add_to_order(cart, self.course_id, self.cost, 'honor') with patch('shoppingcart.models.CertificateItem.save', side_effect=DatabaseError): with self.assertRaises(DatabaseError): cart.purchase() @@ -100,7 +101,7 @@ class OrderTest(TestCase): def purchase_with_data(self, cart): """ purchase a cart with billing information """ - CertificateItem.add_to_order(cart, self.course_id, self.cost, 'verified') + CertificateItem.add_to_order(cart, self.course_id, self.cost, 'honor') cart.purchase( first='John', last='Smith', @@ -232,6 +233,16 @@ class CertificateItemTest(TestCase): self.user = UserFactory.create() self.course_id = "test/course" self.cost = 40 + course_mode = CourseMode(course_id=self.course_id, + mode_slug="honor", + mode_display_name="honor cert", + min_price=self.cost) + course_mode.save() + course_mode = CourseMode(course_id=self.course_id, + mode_slug="verified", + mode_display_name="verified cert", + min_price=self.cost) + course_mode.save() def test_existing_enrollment(self): CourseEnrollment.enroll(self.user, self.course_id) diff --git a/lms/djangoapps/shoppingcart/tests/test_views.py b/lms/djangoapps/shoppingcart/tests/test_views.py index f428fe80b5..b5aea28edd 100644 --- a/lms/djangoapps/shoppingcart/tests/test_views.py +++ b/lms/djangoapps/shoppingcart/tests/test_views.py @@ -91,7 +91,7 @@ class ShoppingCartViewsTests(ModuleStoreTestCase): def test_show_cart(self): self.login_user() reg_item = PaidCourseRegistration.add_to_order(self.cart, self.course_id) - cert_item = CertificateItem.add_to_order(self.cart, 'test/course1', self.cost, 'verified') + cert_item = CertificateItem.add_to_order(self.cart, 'test/course1', self.cost, 'honor') resp = self.client.get(reverse('shoppingcart.views.show_cart', args=[])) self.assertEqual(resp.status_code, 200) @@ -110,7 +110,7 @@ class ShoppingCartViewsTests(ModuleStoreTestCase): def test_clear_cart(self): self.login_user() PaidCourseRegistration.add_to_order(self.cart, self.course_id) - CertificateItem.add_to_order(self.cart, 'test/course1', self.cost, 'verified') + CertificateItem.add_to_order(self.cart, 'test/course1', self.cost, 'honor') self.assertEquals(self.cart.orderitem_set.count(), 2) resp = self.client.post(reverse('shoppingcart.views.clear_cart', args=[])) self.assertEqual(resp.status_code, 200) @@ -120,7 +120,7 @@ class ShoppingCartViewsTests(ModuleStoreTestCase): def test_remove_item(self, exception_log): self.login_user() reg_item = PaidCourseRegistration.add_to_order(self.cart, self.course_id) - cert_item = CertificateItem.add_to_order(self.cart, 'test/course1', self.cost, 'verified') + cert_item = CertificateItem.add_to_order(self.cart, 'test/course1', self.cost, 'honor') self.assertEquals(self.cart.orderitem_set.count(), 2) resp = self.client.post(reverse('shoppingcart.views.remove_item', args=[]), {'id': reg_item.id}) @@ -166,7 +166,7 @@ class ShoppingCartViewsTests(ModuleStoreTestCase): def test_show_receipt_404s(self): PaidCourseRegistration.add_to_order(self.cart, self.course_id) - CertificateItem.add_to_order(self.cart, 'test/course1', self.cost, 'verified') + CertificateItem.add_to_order(self.cart, 'test/course1', self.cost, 'honor') self.cart.purchase() user2 = UserFactory.create() @@ -184,7 +184,7 @@ class ShoppingCartViewsTests(ModuleStoreTestCase): @patch('shoppingcart.views.render_to_response', render_mock) def test_show_receipt_success(self): reg_item = PaidCourseRegistration.add_to_order(self.cart, self.course_id) - cert_item = CertificateItem.add_to_order(self.cart, 'test/course1', self.cost, 'verified') + cert_item = CertificateItem.add_to_order(self.cart, 'test/course1', self.cost, 'honor') self.cart.purchase(first='FirstNameTesting123', street1='StreetTesting123') self.login_user() @@ -203,7 +203,7 @@ class ShoppingCartViewsTests(ModuleStoreTestCase): @patch('shoppingcart.views.render_to_response', render_mock) def test_show_receipt_success_refund(self): reg_item = PaidCourseRegistration.add_to_order(self.cart, self.course_id) - cert_item = CertificateItem.add_to_order(self.cart, 'test/course1', self.cost, 'verified') + cert_item = CertificateItem.add_to_order(self.cart, 'test/course1', self.cost, 'honor') self.cart.purchase(first='FirstNameTesting123', street1='StreetTesting123') cert_item.status = "refunded" cert_item.save() @@ -222,7 +222,7 @@ class ShoppingCartViewsTests(ModuleStoreTestCase): @patch('shoppingcart.views.render_to_response', render_mock) def test_show_receipt_success_custom_receipt_page(self): - cert_item = CertificateItem.add_to_order(self.cart, self.course_id, self.cost, 'verified') + cert_item = CertificateItem.add_to_order(self.cart, self.course_id, self.cost, 'honor') self.cart.purchase() self.login_user() receipt_url = reverse('shoppingcart.views.show_receipt', args=[self.cart.id]) diff --git a/lms/templates/emails/order_confirmation_email.txt b/lms/templates/emails/order_confirmation_email.txt index b6df9f2f00..43d03ce667 100644 --- a/lms/templates/emails/order_confirmation_email.txt +++ b/lms/templates/emails/order_confirmation_email.txt @@ -1,15 +1,20 @@ <%! from django.utils.translation import ugettext as _ %> +${_("Hi {name}").format(name=order.user.first_name)} -${_("Thank you for your order! Payment was successful, and you should be able to see the results on your dashboard.")} +${_("Your payment was successful. You will see the charge below on your next credit or debit card statement. The charge will show up on your statement under the company name {platform_name}. If you have billing questions, please read the FAQ or contact {billing_email}. We hope you enjoy your order.").format(platform_name=settings.PLATFORM_NAME,billing_email=settings.PAYMENT_SUPPORT_EMAIL)} + +${_("-The {platform_name} Team").format(platform_name=settings.PLATFORM_NAME)} ${_("Your order number is: {order_number}").format(order_number=order.id)} -${_("Items in your order:")} +${_("The items in your order are:")} ${_("Quantity - Description - Price")} %for order_item in order_items: ${order_item.qty} - ${order_item.line_desc} - ${order_item.line_cost} %endfor -${_("Total: {total_cost}").format(total_cost=order.total_cost)} +${_("Total billed to credit/debit card: {total_cost}").format(total_cost=order.total_cost)} -${_("If you have any issues, please contact us at {billing_email}").format(billing_email=settings.PAYMENT_SUPPORT_EMAIL)} +%for order_item in order_items: + ${order_item.additional_instruction_text} +%endfor