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(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 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_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_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_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 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_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 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, 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 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 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(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_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 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_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 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 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 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 create_order(self, user=None, credit=False, multiple_lines=False, free=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) else: basket.add_product(self.verified_product) order = create_order(basket=basket, user=user) order.status = status order.save() return order
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 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_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 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 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_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)