def test_generate_receipt_instructions_callchain(self): """ This tests the generate_receipt_instructions call chain (ie calling the function on the cart also calls it on items in the cart """ mock_gen_inst = MagicMock(return_value=(OrderItemSubclassPK(OrderItem, 1), set([]))) cart = Order.get_cart_for_user(self.user) item = OrderItem(user=self.user, order=cart) item.save() self.assertTrue(cart.has_items()) with patch.object(OrderItem, 'generate_receipt_instructions', mock_gen_inst): cart.generate_receipt_instructions() mock_gen_inst.assert_called_with()
class OrderTest(ModuleStoreTestCase): def setUp(self): self.user = UserFactory.create() course = CourseFactory.create() self.course_key = course.id self.other_course_keys = [] for __ in xrange(1, 5): self.other_course_keys.append(CourseFactory.create().id) self.cost = 40 def test_get_cart_for_user(self): # create a cart cart = Order.get_cart_for_user(user=self.user) # add something to it CertificateItem.add_to_order(cart, self.course_key, 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_user_cart_has_items(self): anon = AnonymousUser() self.assertFalse(Order.user_cart_has_items(anon)) self.assertFalse(Order.user_cart_has_items(self.user)) cart = Order.get_cart_for_user(self.user) item = OrderItem(order=cart, user=self.user) item.save() self.assertTrue(Order.user_cart_has_items(self.user)) self.assertFalse(Order.user_cart_has_items(self.user, CertificateItem)) self.assertFalse(Order.user_cart_has_items(self.user, PaidCourseRegistration)) def test_user_cart_has_paid_course_registration_items(self): cart = Order.get_cart_for_user(self.user) item = PaidCourseRegistration(order=cart, user=self.user) item.save() self.assertTrue(Order.user_cart_has_items(self.user, PaidCourseRegistration)) self.assertFalse(Order.user_cart_has_items(self.user, CertificateItem)) def test_user_cart_has_certificate_items(self): cart = Order.get_cart_for_user(self.user) CertificateItem.add_to_order(cart, self.course_key, self.cost, 'honor') self.assertTrue(Order.user_cart_has_items(self.user, CertificateItem)) self.assertFalse(Order.user_cart_has_items(self.user, PaidCourseRegistration)) def test_cart_clear(self): cart = Order.get_cart_for_user(user=self.user) CertificateItem.add_to_order(cart, self.course_key, self.cost, 'honor') CertificateItem.add_to_order(cart, self.other_course_keys[0], self.cost, 'honor') self.assertEquals(cart.orderitem_set.count(), 2) self.assertTrue(cart.has_items()) cart.clear() self.assertEquals(cart.orderitem_set.count(), 0) self.assertFalse(cart.has_items()) 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_key, 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_key, self.cost, 'honor', currency='usd') # assert that this item did not get added to the cart self.assertEquals(cart.orderitem_set.count(), 1) def test_total_cost(self): cart = Order.get_cart_for_user(user=self.user) # add items to the order course_costs = [(self.other_course_keys[0], 30), (self.other_course_keys[1], 40), (self.other_course_keys[2], 10), (self.other_course_keys[3], 20)] for course, cost in course_costs: 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)) def test_start_purchase(self): # Start the purchase, which will mark the cart as "paying" cart = Order.get_cart_for_user(user=self.user) CertificateItem.add_to_order(cart, self.course_key, self.cost, 'honor', currency='usd') cart.start_purchase() self.assertEqual(cart.status, 'paying') for item in cart.orderitem_set.all(): self.assertEqual(item.status, 'paying') # Starting the purchase should be idempotent cart.start_purchase() self.assertEqual(cart.status, 'paying') for item in cart.orderitem_set.all(): self.assertEqual(item.status, 'paying') # If we retrieve the cart for the user, we should get a different order next_cart = Order.get_cart_for_user(user=self.user) self.assertNotEqual(cart, next_cart) self.assertEqual(next_cart.status, 'cart') # Complete the first purchase cart.purchase() self.assertEqual(cart.status, 'purchased') for item in cart.orderitem_set.all(): self.assertEqual(item.status, 'purchased') # Starting the purchase again should be a no-op cart.start_purchase() self.assertEqual(cart.status, 'purchased') for item in cart.orderitem_set.all(): self.assertEqual(item.status, 'purchased') def test_purchase(self): # This test is for testing the subclassing functionality of OrderItem, but in # order to do this, we end up testing the specific functionality of # 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_key)) item = CertificateItem.add_to_order(cart, self.course_key, self.cost, 'honor') # course enrollment object should be created but still inactive self.assertFalse(CourseEnrollment.is_enrolled(self.user, self.course_key)) cart.purchase() self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course_key)) # test e-mail sending self.assertEquals(len(mail.outbox), 1) 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_key, self.cost, 'honor') with patch('shoppingcart.models.CertificateItem.save', side_effect=DatabaseError): with self.assertRaises(DatabaseError): cart.purchase() # verify that we rolled back the entire transaction self.assertFalse(CourseEnrollment.is_enrolled(self.user, self.course_key)) # verify that e-mail wasn't sent self.assertEquals(len(mail.outbox), 0) def test_purchase_twice(self): cart = Order.get_cart_for_user(self.user) CertificateItem.add_to_order(cart, self.course_key, self.cost, 'honor') # purchase the cart more than once cart.purchase() cart.purchase() self.assertEquals(len(mail.outbox), 1) @patch('shoppingcart.models.log.error') def test_purchase_item_email_smtp_failure(self, error_logger): cart = Order.get_cart_for_user(user=self.user) CertificateItem.add_to_order(cart, self.course_key, self.cost, 'honor') with patch('shoppingcart.models.send_mail', side_effect=smtplib.SMTPException): cart.purchase() self.assertTrue(error_logger.called) @patch('shoppingcart.models.log.error') def test_purchase_item_email_boto_failure(self, error_logger): cart = Order.get_cart_for_user(user=self.user) CertificateItem.add_to_order(cart, self.course_key, self.cost, 'honor') with patch('shoppingcart.models.send_mail', side_effect=BotoServerError("status", "reason")): cart.purchase() self.assertTrue(error_logger.called) def purchase_with_data(self, cart): """ purchase a cart with billing information """ CertificateItem.add_to_order(cart, self.course_key, self.cost, 'honor') cart.purchase( first='John', last='Smith', street1='11 Cambridge Center', street2='Suite 101', city='Cambridge', state='MA', postalcode='02412', country='US', ccnum='1111', cardtype='001', ) @patch('shoppingcart.models.render_to_string') @patch.dict(settings.FEATURES, {'STORE_BILLING_INFO': True}) def test_billing_info_storage_on(self, render): cart = Order.get_cart_for_user(self.user) self.purchase_with_data(cart) self.assertNotEqual(cart.bill_to_first, '') self.assertNotEqual(cart.bill_to_last, '') self.assertNotEqual(cart.bill_to_street1, '') self.assertNotEqual(cart.bill_to_street2, '') self.assertNotEqual(cart.bill_to_postalcode, '') self.assertNotEqual(cart.bill_to_ccnum, '') self.assertNotEqual(cart.bill_to_cardtype, '') self.assertNotEqual(cart.bill_to_city, '') self.assertNotEqual(cart.bill_to_state, '') self.assertNotEqual(cart.bill_to_country, '') ((_, context), _) = render.call_args self.assertTrue(context['has_billing_info']) @patch('shoppingcart.models.render_to_string') @patch.dict(settings.FEATURES, {'STORE_BILLING_INFO': False}) def test_billing_info_storage_off(self, render): cart = Order.get_cart_for_user(self.user) self.purchase_with_data(cart) self.assertNotEqual(cart.bill_to_first, '') self.assertNotEqual(cart.bill_to_last, '') self.assertNotEqual(cart.bill_to_city, '') self.assertNotEqual(cart.bill_to_state, '') self.assertNotEqual(cart.bill_to_country, '') self.assertNotEqual(cart.bill_to_postalcode, '') # things we expect to be missing when the feature is off self.assertEqual(cart.bill_to_street1, '') self.assertEqual(cart.bill_to_street2, '') self.assertEqual(cart.bill_to_ccnum, '') self.assertEqual(cart.bill_to_cardtype, '') ((_, context), _) = render.call_args self.assertFalse(context['has_billing_info']) mock_gen_inst = MagicMock(return_value=(OrderItemSubclassPK(OrderItem, 1), set([]))) def test_generate_receipt_instructions_callchain(self): """ This tests the generate_receipt_instructions call chain (ie calling the function on the cart also calls it on items in the cart """ cart = Order.get_cart_for_user(self.user) item = OrderItem(user=self.user, order=cart) item.save() self.assertTrue(cart.has_items()) with patch.object(OrderItem, 'generate_receipt_instructions', self.mock_gen_inst): cart.generate_receipt_instructions() self.mock_gen_inst.assert_called_with()