def test_non_free_basket_order(self, __): """ Verify an error is raised for non-free basket. """ basket = BasketFactory(owner=self.user, site=self.site) basket.add_product(ProductFactory(stockrecords__price_excl_tax=10)) with self.assertRaises(BasketNotFreeError): EdxOrderPlacementMixin().place_free_order(basket)
def test_track_completed_discounted_order_with_offer(self): """ An event including a discount but no coupon should be sent to Segment""" with mock.patch( 'ecommerce.extensions.checkout.signals.track_segment_event' ) as mock_track: # Orders may be discounted by a fixed value offer_discount = 5 product = ProductFactory(categories=[], stockrecords__price_currency='USD') _range = factories.RangeFactory(products=[product], ) site_offer = factories.ConditionalOfferFactory( offer_type=ConditionalOffer.SITE, benefit=factories.BenefitFactory(range=_range, value=offer_discount), condition=factories.ConditionFactory(type=Condition.COVERAGE, value=1, range=_range)) basket = BasketFactory(owner=self.user, site=self.site) basket.add_product(product) Applicator().apply_offers(basket, [site_offer]) order = factories.create_order(basket=basket, user=self.user) track_completed_order(None, order) properties = self._generate_event_properties(order) mock_track.assert_called_once_with(order.site, order.user, 'Order Completed', properties)
def test_track_completed_discounted_order_with_voucher_with_offer(self): with mock.patch( 'ecommerce.extensions.checkout.signals.track_segment_event' ) as mock_track: # Orders may be discounted by a fixed value fixed_benefit = 5.00 offer_discount = 6 product = ProductFactory(categories=[], stockrecords__price_currency='USD') _range = factories.RangeFactory(products=[product], ) voucher, product = prepare_voucher(_range=_range, benefit_value=fixed_benefit, benefit_type=Benefit.FIXED) factories.ConditionalOfferFactory( offer_type=ConditionalOffer.SITE, benefit=factories.BenefitFactory(range=_range, value=offer_discount), condition=factories.ConditionFactory(type=Condition.COVERAGE, value=1, range=_range)) basket = BasketFactory(owner=self.user, site=self.site) basket.add_product(product) basket.vouchers.add(voucher) Applicator().apply(basket, user=basket.owner, request=self.request) order = factories.create_order(basket=basket, user=self.user) track_completed_order(None, order) properties = self._generate_event_properties(order, voucher) mock_track.assert_called_once_with(order.site, order.user, 'Order Completed', properties)
def test_track_completed_enrollment_order(self): """ Make sure we do not send GA events for Enrollment Code orders """ with mock.patch( 'ecommerce.extensions.checkout.signals.track_segment_event' ) as mock_track: toggle_switch(ENROLLMENT_CODE_SWITCH, True) site_config = self.site.siteconfiguration site_config.enable_enrollment_codes = True site_config.save() course = CourseFactory() course.create_or_update_seat('verified', True, 50, self.partner, create_enrollment_code=True) enrollment_code = Product.objects.get( product_class__name=ENROLLMENT_CODE_PRODUCT_CLASS_NAME) basket = BasketFactory(owner=self.user, site=self.site) basket.add_product(enrollment_code) order = factories.create_order(basket=basket, user=self.user) track_completed_order(None, order) assert not mock_track.called
def setUp(self): super(CouponFulfillmentModuleTest, self).setUp() coupon = self.create_coupon() user = UserFactory() basket = BasketFactory() basket.add_product(coupon, 1) self.order = factories.create_order(number=1, basket=basket, user=user)
def test_place_free_order(self, __): """ Verify an order is placed and the basket is submitted. """ basket = BasketFactory(owner=self.user, site=self.site) basket.add_product(ProductFactory(stockrecords__price_excl_tax=0)) order = EdxOrderPlacementMixin().place_free_order(basket) self.assertIsNotNone(order) self.assertEqual(basket.status, Basket.SUBMITTED)
def _create_order(self, price): seat = self.course.create_or_update_seat('verified', False, price, self.partner, None) basket = BasketFactory() basket.add_product(seat, 1) order = create_order(number=1, basket=basket, user=self.user) order.total_excl_tax = price return seat, order
def _create_order(self, price, mode='verified'): seat = self.course.create_or_update_seat(mode, False, price, self.partner, None) basket = BasketFactory() basket.add_product(seat, 1) order = create_order(number=1, basket=basket, user=self.user, site=self.site) order.total_excl_tax = price return seat, order
def create_order_number(self): """Test creating order numbers""" basket = BasketFactory() next_basket = BasketFactory() new_order_number = OrderNumberGenerator.order_number(basket) next_order_number = OrderNumberGenerator.order_number(next_basket) self.assertIn(self.ORDER_NUMBER_PREFIX, new_order_number) self.assertIn(self.ORDER_NUMBER_PREFIX, next_order_number) self.assertNotEqual(new_order_number, next_order_number)
def setUp(self): super(EnrollmentFulfillmentTestMixin, self).setUp() user = UserFactory() course = Course.objects.create(id=self.course_id, name='Demo Course') self.seat = course.create_or_update_seat(self.certificate_type, False, 100, self.provider) basket = BasketFactory() basket.add_product(self.seat, 1) self.order = factories.create_order(number=1, basket=basket, user=user)
def setUp(self): super(EnrollmentCodeFulfillmentModuleTests, self).setUp() toggle_switch(ENROLLMENT_CODE_SWITCH, True) course = CourseFactory() course.create_or_update_seat('verified', True, 50, self.partner, create_enrollment_code=True) enrollment_code = Product.objects.get(product_class__name=ENROLLMENT_CODE_PRODUCT_CLASS_NAME) user = UserFactory() basket = BasketFactory(owner=user, site=self.site) basket.add_product(enrollment_code, self.QUANTITY) self.order = create_order(number=1, basket=basket, user=user)
def setUp(self): super(EnrollmentCodeFulfillmentModuleTests, self).setUp() toggle_switch(ENROLLMENT_CODE_SWITCH, True) course = CourseFactory() course.create_or_update_seat('verified', True, 50, self.partner) enrollment_code = Product.objects.get(product_class__name=ENROLLMENT_CODE_PRODUCT_CLASS_NAME) user = UserFactory() basket = BasketFactory() basket.add_product(enrollment_code, self.QUANTITY) self.order = factories.create_order(number=1, basket=basket, user=user)
def setUp(self): super(EnrollmentFulfillmentModuleTests, self).setUp() self.user = UserFactory() self.course = CourseFactory(id=self.course_id, name='Demo Course', site=self.site) self.seat = self.course.create_or_update_seat(self.certificate_type, False, 100, self.partner, self.provider) basket = BasketFactory(owner=self.user, site=self.site) basket.add_product(self.seat, 1) self.order = create_order(number=1, basket=basket, user=self.user)
def test_track_completed_coupon_order(self): """ Make sure we do not send GA events for Coupon orders """ with mock.patch( 'ecommerce.extensions.checkout.signals.track_segment_event' ) as mock_track: coupon = self.create_coupon() basket = BasketFactory(owner=self.user, site=self.site) basket.add_product(coupon) order = factories.create_order(basket=basket, user=self.user) track_completed_order(None, order) assert not mock_track.called
def test_unsupported_product_class(self, mock_log_error, mock_update_course_enrollment): """ Verify Sailthru is not contacted for non-seat products. """ coupon = self.create_coupon() basket = BasketFactory() basket.add_product(coupon, 1) process_basket_addition(None, request=self.request, user=self.user, product=coupon, basket=basket) self.assertFalse(mock_update_course_enrollment.called) self.assertFalse(mock_log_error.called) order = create_order(number=1, basket=basket, user=self.user) process_checkout_complete(None, order=order, request=None) self.assertFalse(mock_update_course_enrollment.called) self.assertFalse(mock_log_error.called)
def setUp(self): super(DonationsFromCheckoutTestFulfillmentModuleTest, self).setUp() donation_class = ProductClass.objects.get( name=DONATIONS_FROM_CHECKOUT_TESTS_PRODUCT_TYPE_NAME, track_stock=False) donation = factories.create_product(product_class=donation_class, title='Test product') user = UserFactory() basket = BasketFactory(owner=user, site=self.site) factories.create_stockrecord(donation, num_in_stock=2, price_excl_tax=10) basket.add_product(donation, 1) self.order = create_order(number=1, basket=basket, user=user)
def test_post_checkout_callback(self): """ When the post_checkout signal is emitted, the receiver should attempt to fulfill the newly-placed order and send receipt email. """ httpretty.register_uri(httpretty.GET, get_lms_url('api/credit/v1/providers/ASU'), body='{"display_name": "Hogwarts"}', content_type="application/json") toggle_switch('ENABLE_NOTIFICATIONS', True) course = Course.objects.create(id='edX/DemoX/Demo_Course', name='Demo Course') seat = course.create_or_update_seat('credit', False, 50, self.partner, 'ASU', None, 2) basket = BasketFactory() basket.add_product(seat, 1) order = factories.create_order(number=1, basket=basket, user=self.user) with mock.patch( 'threadlocals.threadlocals.get_current_request') as mock_gcr: mock_gcr.return_value = self.request send_course_purchase_email(None, order=order) self.assertEqual(len(mail.outbox), 1) self.assertEqual(mail.outbox[0].from_email, self.site_configuration.from_email) self.assertEqual(mail.outbox[0].subject, 'Order Receipt') self.assertEqual( mail.outbox[0].body, '\nPayment confirmation for: {course_title}' '\n\nDear {full_name},' '\n\nThank you for purchasing {credit_hours} credit hours from {credit_provider} for {course_title}. ' 'A charge will appear on your credit or debit card statement with a company name of "{platform_name}".' '\n\nTo receive your course credit, you must also request credit at the {credit_provider} website. ' 'For a link to request credit from {credit_provider}, or to see the status of your credit request, ' 'go to your {platform_name} dashboard.' '\n\nTo explore other credit-eligible courses, visit the {platform_name} website. ' 'We add new courses frequently!' '\n\nTo view your payment information, visit the following website.' '\n{receipt_url}' '\n\nThank you. We hope you enjoyed your course!' '\nThe {platform_name} team' '\n\nYou received this message because you purchased credit hours for {course_title}, ' 'an {platform_name} course.\n'.format( course_title=order.lines.first().product.title, full_name=self.user.get_full_name(), credit_hours=2, credit_provider='Hogwarts', platform_name=get_current_request().site.name, receipt_url=get_lms_url('{}?orderNum={}'.format( settings.RECEIPT_PAGE_PATH, order.number))))
def test_post_checkout_callback(self): """ When the post_checkout signal is emitted, the receiver should attempt to fulfill the newly-placed order and send receipt email. """ httpretty.register_uri( httpretty.GET, get_lms_url('api/credit/v1/providers/ASU'), body='{"display_name": "Hogwarts"}', content_type="application/json" ) toggle_switch('ENABLE_NOTIFICATIONS', True) course = Course.objects.create(id='edX/DemoX/Demo_Course', name='Demo Course') seat = course.create_or_update_seat('credit', False, 50, self.partner, 'ASU', None, 2) basket = BasketFactory() basket.add_product(seat, 1) order = factories.create_order(number=1, basket=basket, user=self.user) with mock.patch('threadlocals.threadlocals.get_current_request') as mock_gcr: mock_gcr.return_value = self.request send_course_purchase_email(None, order=order) self.assertEqual(len(mail.outbox), 1) self.assertEqual(mail.outbox[0].from_email, self.site_configuration.from_email) self.assertEqual(mail.outbox[0].subject, 'Order Receipt') self.assertEqual( mail.outbox[0].body, '\nPayment confirmation for: {course_title}' '\n\nDear {full_name},' '\n\nThank you for purchasing {credit_hours} credit hours from {credit_provider} for {course_title}. ' 'A charge will appear on your credit or debit card statement with a company name of "{platform_name}".' '\n\nTo receive your course credit, you must also request credit at the {credit_provider} website. ' 'For a link to request credit from {credit_provider}, or to see the status of your credit request, ' 'go to your {platform_name} dashboard.' '\n\nTo explore other credit-eligible courses, visit the {platform_name} website. ' 'We add new courses frequently!' '\n\nTo view your payment information, visit the following website.' '\n{receipt_url}' '\n\nThank you. We hope you enjoyed your course!' '\nThe {platform_name} team' '\n\nYou received this message because you purchased credit hours for {course_title}, ' 'an {platform_name} course.\n'.format( course_title=order.lines.first().product.title, full_name=self.user.get_full_name(), credit_hours=2, credit_provider='Hogwarts', platform_name=get_current_request().site.name, receipt_url=get_lms_url('{}?orderNum={}'.format(settings.RECEIPT_PAGE_PATH, order.number)) ) )
def create_seat_and_order(self, certificate_type='test-certificate-type', provider=None): """ Create the certificate of given type and seat of given provider. Arguments: certificate_type(str): The type of certificate provider(str): The provider ID. Returns: None """ self.certificate_type = certificate_type self.provider = provider self.seat = self.course.create_or_update_seat(self.certificate_type, False, 100, self.partner, self.provider) basket = BasketFactory() basket.add_product(self.seat, 1) self.order = factories.create_order(number=2, basket=basket, user=self.user)
def create_seat_and_order(self, certificate_type='test-certificate-type', provider=None): """ Create the certificate of given type and seat of given provider. Arguments: certificate_type(str): The type of certificate provider(str): The provider ID. Returns: None """ self.certificate_type = certificate_type self.provider = provider self.seat = self.course.create_or_update_seat(self.certificate_type, False, 100, self.partner, self.provider) basket = BasketFactory(owner=self.user, site=self.site) basket.add_product(self.seat, 1) self.order = create_order(number=2, basket=basket, user=self.user)
def prepare_order(self, seat_type, credit_provider_id=None): """ Prepares order for a post-checkout test. Args: seat_type (str): Course seat type credit_provider_id (str): Credit provider associated with the course seat. Returns: Order """ course = CourseFactory() seat = course.create_or_update_seat(seat_type, False, 50, self.partner, credit_provider_id, None, 2) basket = BasketFactory(site=self.site) basket.add_product(seat, 1) order = factories.create_order(basket=basket, user=self.user) return order
def test_order_number_from_basket_id(self): """ Verify the method returns an order number determined using the basket's ID, and the specified partner. """ basket = BasketFactory() acme = PartnerFactory(name='ACME') for partner in (self.partner, acme,): self.assertEqual(self.generator.order_number_from_basket_id(partner, basket.id), '{}-{}'.format(partner.short_code.upper(), 100000 + basket.id))
def setUp(self): super(EntitlementFulfillmentModuleTests, self).setUp() self.user = UserFactory() self.course_entitlement = create_or_update_course_entitlement( 'verified', 100, self.partner, '111-222-333-444', 'Course Entitlement') basket = BasketFactory(owner=self.user, site=self.site) basket.add_product(self.course_entitlement, 1) self.entitlement_option = Option.objects.get(name='Course Entitlement') self.order = create_order(number=1, basket=basket, user=self.user) self.logger_name = 'ecommerce.extensions.fulfillment.modules' self.return_data = { "user": "******", "course_uuid": "3b3123b8-d34b-44d8-9bbb-a12676e97123", "uuid": "111-222-333", "mode": "verified", "expired_at": "None" }
def test_post_checkout_callback(self): """ When the post_checkout signal is emitted, the receiver should attempt to fulfill the newly-placed order and send receipt email. """ httpretty.register_uri( httpretty.GET, get_lms_url('api/credit/v1/providers/ASU'), body='{"display_name": "Hogwarts"}', content_type="application/json" ) toggle_switch('ENABLE_NOTIFICATIONS', True) user = UserFactory() course = Course.objects.create(id='edX/DemoX/Demo_Course', name='Demo Course') partner = self.create_partner('edx') seat = course.create_or_update_seat('credit', False, 50, partner, 'ASU', None, 2) basket = BasketFactory() basket.add_product(seat, 1) order = factories.create_order(number=1, basket=basket, user=user) send_course_purchase_email(None, order=order) self.assertEqual(len(mail.outbox), 1) self.assertEqual(mail.outbox[0].subject, 'Order Receipt') self.assertEqual( mail.outbox[0].body, '\nReceipt Confirmation for: {course_name}' '\n\nHi {full_name},\n\n' 'Thank you for purchasing {credit_hour} credit hours from {provider_name} for {course_name}.' ' The charge below will appear on your next credit or debit card statement with a ' 'company name of {platform_name}.\n\nYou can see the status the status of your credit request or ' 'complete the credit request process on your {platform_name} dashboard\nTo browse other ' 'credit-eligible courses visit the edX website. More courses are added all the time.\n\n' 'Thank you and congratulation on your achievement. We hope you enjoy the course!\n\n' 'To view receipt please visit the link below' '\n\n{receipt_url}\n\n' '{platform_name} team\n\nThe edX team\n'.format( course_name=order.lines.first().product.title, full_name=user.get_full_name(), credit_hour=2, provider_name='Hogwarts', platform_name=settings.PLATFORM_NAME, receipt_url=get_lms_url('/commerce/checkout/receipt/?basket_id={}'.format(order.basket.id)) ) )
def test_order_number_for_basket_without_site(self): """ Verify the order number is linked to the default site, if the basket has no associated site. """ site_configuration = SiteConfigurationFactory(site__domain='acme.fake', partner__name='ACME') site = site_configuration.site partner = site_configuration.partner basket = BasketFactory(site=None) with override_settings(SITE_ID=site.id): self.assert_order_number_matches_basket(basket, partner)
def create_order(self, user=None, multiple_lines=False, free=False): user = user or self.user basket = BasketFactory(owner=user) if multiple_lines: basket.add_product(self.verified_product) basket.add_product(self.honor_product) elif free: basket.add_product(self.honor_product) else: basket.add_product(self.verified_product) order = create_order(basket=basket, user=user) order.status = ORDER.COMPLETE order.save() return order
def create_order(self, user=None, multiple_lines=False, free=False, status=ORDER.COMPLETE): user = user or self.user basket = BasketFactory(owner=user) if multiple_lines: basket.add_product(self.verified_product) basket.add_product(self.honor_product) elif free: basket.add_product(self.honor_product) else: basket.add_product(self.verified_product) order = create_order(basket=basket, user=user) order.status = status order.save() return order
def setUp(self): super(EnrollmentFulfillmentModuleTests, self).setUp() self.user = UserFactory() self.user.tracking_context = { 'ga_client_id': 'test-client-id', 'lms_user_id': 'test-user-id', 'lms_ip': '127.0.0.1' } self.user.save() self.course = CourseFactory(id=self.course_id, name='Demo Course', site=self.site) self.seat = self.course.create_or_update_seat(self.certificate_type, False, 100, self.partner, self.provider) basket = BasketFactory(owner=self.user, site=self.site) basket.add_product(self.seat, 1) self.order = create_order(number=1, basket=basket, user=self.user)
def test_order_number_for_basket_without_site(self): """ Verify the order number is linked to the default site, if the basket has no associated site. """ site_configuration = SiteConfigurationFactory(site__domain='acme.fake', partner__name='ACME') site = site_configuration.site partner = site_configuration.partner basket = BasketFactory(site=None) request = RequestFactory().get('') request.session = None request.site = site with mock.patch('ecommerce.extensions.order.utils.get_current_request', mock.Mock(return_value=request)): self.assert_order_number_matches_basket(basket, partner)
def test_prof_ed_stale_product_removal_with_orders(self): """ Verify that professional education seats are never deleted if they have been purchased. """ user = self.create_user() course = CourseFactory() professional_product_no_verification = course.create_or_update_seat('professional', False, 0, self.partner) self.assertEqual(course.products.count(), 2) basket = BasketFactory(owner=user) basket.add_product(professional_product_no_verification) create_order(basket=basket, user=user) course.create_or_update_seat('professional', True, 0, self.partner) self.assertEqual(course.products.count(), 3) product_mode = course.products.all()[0] self.assertEqual(product_mode.attr.id_verification_required, True) self.assertEqual(product_mode.attr.certificate_type, 'professional') product_mode = course.products.all()[1] self.assertEqual(product_mode.attr.id_verification_required, False) self.assertEqual(product_mode.attr.certificate_type, 'professional')
def setUp(self): user = UserFactory() self.product_class = factories.ProductClassFactory( name='Seat', requires_shipping=False, track_stock=False ) self.course = factories.ProductFactory( structure='parent', upc='001', title='EdX DemoX Course', product_class=self.product_class ) self.seat = factories.ProductFactory( structure='child', upc='002', title='Seat in EdX DemoX Course with Honor Certificate', product_class=None, parent=self.course ) for stock_record in self.seat.stockrecords.all(): stock_record.price_currency = 'USD' stock_record.save() basket = BasketFactory() basket.add_product(self.seat, 1) self.order = factories.create_order(number=1, basket=basket, user=user)
def test_track_completed_discounted_order_with_voucher(self): """ An event including coupon information should be sent to Segment""" with mock.patch( 'ecommerce.extensions.checkout.signals.track_segment_event' ) as mock_track: # Orders may be discounted by percent percent_benefit = 66 product = ProductFactory(categories=[], stockrecords__price_currency='USD') _range = factories.RangeFactory(products=[product], ) voucher, product = prepare_voucher(_range=_range, benefit_value=percent_benefit) basket = BasketFactory(owner=self.user, site=self.site) basket.add_product(product) basket.vouchers.add(voucher) Applicator().apply(basket, user=basket.owner, request=self.request) order = factories.create_order(basket=basket, user=self.user) track_completed_order(None, order) properties = self._generate_event_properties(order, voucher) mock_track.assert_called_once_with(order.site, order.user, 'Order Completed', properties)
def test_stop_sailthru_update_on_multi_product_baskets(self, mock_log_error, mock_update_course_enrollment): """ Verify Sailthru is not contacted for multi-product baskets. """ # Create multi-product basket seat = self.course.create_or_update_seat('verified', False, 100, self.partner, None) other_course = CourseFactory(site=self.site) other_seat = other_course.create_or_update_seat('verified', False, 100, self.partner, None) basket = BasketFactory(owner=self.user, site=self.site) basket.add_product(seat) basket.add_product(other_seat) multi_product_order = create_order(number=2, basket=basket, user=self.user, site=self.site) # This method takes an argument to determine whether that product is part of a multi-product basket process_basket_addition(None, request=self.request, user=self.user, product=seat, is_multi_product_basket=True) self.assertFalse(mock_update_course_enrollment.called) self.assertFalse(mock_log_error.called) # This method looks at the number of lines in the order to determine if the basket has multiple products process_checkout_complete(None, order=multi_product_order, request=None) self.assertFalse(mock_update_course_enrollment.called) self.assertFalse(mock_log_error.called)
def create_order(self, user=None, credit=False, multiple_lines=False, free=False, entitlement=False, status=ORDER.COMPLETE): user = user or self.user basket = BasketFactory(owner=user, site=self.site) if credit: basket.add_product(self.credit_product) elif multiple_lines: basket.add_product(self.verified_product) basket.add_product(self.honor_product) elif free: basket.add_product(self.honor_product) elif entitlement: course_entitlement = create_or_update_course_entitlement( 'verified', 100, self.partner, '111', 'Foo') basket.add_product(course_entitlement) else: basket.add_product(self.verified_product) order = create_order(basket=basket, user=user) order.status = status if entitlement: entitlement_option = Option.objects.get(code='course_entitlement') line = order.lines.first() line.attributes.create(option=entitlement_option, value='111') order.save() return order
def test_order_number(self): """ Verify the method returns an order number determined using the basket's site/partner and ID. """ basket = BasketFactory(site=self.site) self.assert_order_number_matches_basket(basket, self.partner)