def process_checkout_complete(sender, order=None, request=None, user=None, **kwargs): # pylint: disable=unused-argument """Tell Sailthru when payment done. Arguments: Parameters described at http://django-oscar.readthedocs.io/en/releases-1.1/ref/signals.html """ if not waffle.switch_is_active('sailthru_enable'): return # loop through lines in order # If multi product orders become common it may be worthwhile to pass an array of # orders to the worker in one call to save overhead, however, that would be difficult # because of the fact that there are different templates for free enroll versus paid enroll for line in order.lines.all(): # get product product = line.product # get price price = line.line_price_excl_tax course_id = product.course_id # figure out course url course_url = _build_course_url(course_id) # pass event to ecommerce_worker.sailthru.v1.tasks to handle asynchronously update_course_enrollment.delay(user.email, course_url, False, mode_for_seat(product), unit_cost=price, course_id=course_id, currency=order.currency, site_code=request.site.siteconfiguration.partner.short_code, message_id=request.COOKIES.get('sailthru_bid'))
def test_update_course_purchase(self, mock_sailthru_api_post, mock_sailthru_api_get, mock_sailthru_purchase): """test add purchase to cart""" # create mocked Sailthru API responses mock_sailthru_api_post.return_value = MockSailthruResponse({'ok': True}) mock_sailthru_api_get.return_value = MockSailthruResponse({'tags': 'tag1,tag2', 'title': 'Course title'}) mock_sailthru_purchase.return_value = MockSailthruResponse({'ok': True}) update_course_enrollment.delay(TEST_EMAIL, self.course_url2, True, 'credit', course_id=self.course_id2, currency='USD', message_id='cookie_bid', unit_cost=49) mock_sailthru_purchase.assert_called_with(TEST_EMAIL, [{'vars': {'course_run_id': self.course_id2, 'mode': 'credit'}, 'title': 'Course title', 'url': self.course_url2, 'tags': 'tag1,tag2', 'price': 4900, 'qty': 1, 'id': self.course_id2 + '-credit'}], options={'reminder_template': 'abandoned_template', 'reminder_time': '+60 minutes'}, incomplete=True, message_id='cookie_bid')
def process_basket_addition(sender, product=None, user=None, request=None, **kwargs): # pylint: disable=unused-argument """Tell Sailthru when payment started. Arguments: Parameters described at http://django-oscar.readthedocs.io/en/releases-1.1/ref/signals.html """ if not waffle.switch_is_active('sailthru_enable'): return course_id = product.course_id # figure out course url course_url = _build_course_url(course_id) # get price & currency stock_record = product.stockrecords.first() if stock_record: price = stock_record.price_excl_tax currency = stock_record.price_currency # return if no price, no need to add free items to shopping cart if not price: return # pass event to ecommerce_worker.sailthru.v1.tasks to handle asynchronously update_course_enrollment.delay(user.email, course_url, True, mode_for_seat(product), unit_cost=price, course_id=course_id, currency=currency, site_code=request.site.siteconfiguration.partner.short_code, message_id=request.COOKIES.get('sailthru_bid'))
def test_update_course_enroll(self, mock_sailthru_api_post, mock_sailthru_api_get, mock_sailthru_purchase): """test audit enroll""" # create mocked Sailthru API responses mock_sailthru_api_post.return_value = MockSailthruResponse({'ok': True}) mock_sailthru_api_get.return_value = MockSailthruResponse({'vars': {'upgrade_deadline_verified': '2020-03-12'}}) mock_sailthru_purchase.return_value = MockSailthruResponse({'ok': True}) update_course_enrollment.delay(TEST_EMAIL, self.course_url, False, 'audit', course_id=self.course_id, currency='USD', message_id='cookie_bid', unit_cost=Decimal(0)) mock_sailthru_purchase.assert_called_with(TEST_EMAIL, [{'vars': {'course_run_id': self.course_id, 'mode': 'audit', 'upgrade_deadline_verified': '2020-03-12'}, 'title': 'Course ' + self.course_id + ' mode: audit', 'url': self.course_url, 'price': 100, 'qty': 1, 'id': self.course_id + '-audit'}], options={'send_template': 'enroll_template'}, incomplete=False, message_id='cookie_bid')
def test_update_course_upgrade_complete_site(self, mock_sailthru_api_post, mock_sailthru_api_get, mock_sailthru_purchase): """test upgrade complete with site code""" # create mocked Sailthru API responses mock_sailthru_api_post.return_value = MockSailthruResponse({'ok': True}) mock_sailthru_api_get.return_value = MockSailthruResponse({'vars': {'upgrade_deadline_verified': '2020-03-12'}}) mock_sailthru_purchase.return_value = MockSailthruResponse({'ok': True}) # test upgrade complete with site code with patch('ecommerce_worker.configuration.test.SITE_OVERRIDES', get_configuration('TEST_SITE_OVERRIDES')): update_course_enrollment.delay(TEST_EMAIL, self.course_url, False, 'verified', course_id=self.course_id, currency='USD', message_id='cookie_bid', unit_cost=Decimal(99.01), site_code='test_site') mock_sailthru_purchase.assert_called_with(TEST_EMAIL, [{'vars': {'course_run_id': self.course_id, 'mode': 'verified', 'upgrade_deadline_verified': '2020-03-12'}, 'title': 'Course ' + self.course_id + ' mode: verified', 'url': self.course_url, 'price': 9901, 'qty': 1, 'id': self.course_id + '-verified'}], options={'send_template': 'site_upgrade_template'}, incomplete=False, message_id='cookie_bid')
def process_basket_addition(sender, product=None, request=None, user=None, **kwargs): # pylint: disable=unused-argument """Tell Sailthru when payment started. Arguments: Parameters described at http://django-oscar.readthedocs.io/en/releases-1.1/ref/signals.html """ if not waffle.switch_is_active('sailthru_enable'): return course_id = product.course_id # figure out course url course_url = _build_course_url(course_id) # get price & currency stock_record = product.stockrecords.first() if stock_record: price = stock_record.price_excl_tax currency = stock_record.price_currency # return if no price, no need to add free items to shopping cart if not price: return # pass event to ecommerce_worker.sailthru.v1.tasks to handle asynchronously update_course_enrollment.delay(user.email, course_url, True, mode_for_seat(product), unit_cost=price, course_id=course_id, currency=currency, site_code=request.site.siteconfiguration.partner.short_code, message_id=request.COOKIES.get('sailthru_bid'))
def test_update_course_enroll_skip(self, mock_sailthru_api_post, mock_sailthru_api_get, mock_sailthru_purchase, mock_get_configuration): """test audit enroll with configured cost = 0""" config = get_configuration('SAILTHRU') config['SAILTHRU_MINIMUM_COST'] = 0 mock_get_configuration.return_value = config # create mocked Sailthru API responses mock_sailthru_api_post.return_value = MockSailthruResponse( {'ok': True}) mock_sailthru_api_get.return_value = MockSailthruResponse( {'vars': { 'upgrade_deadline_verified': '2020-03-12' }}) mock_sailthru_purchase.return_value = MockSailthruResponse( {'ok': True}) update_course_enrollment.delay(TEST_EMAIL, self.course_url, False, 'audit', course_id=self.course_id, currency='USD', message_id='cookie_bid', unit_cost=Decimal(0)) mock_sailthru_purchase.assert_not_called()
def test_update_course_upgrade(self, mock_sailthru_api_post, mock_sailthru_api_get, mock_sailthru_purchase): """test add upgrade to cart""" # create mocked Sailthru API responses mock_sailthru_api_post.return_value = MockSailthruResponse({'ok': True}) mock_sailthru_api_get.return_value = MockSailthruResponse({'vars': {'upgrade_deadline_verified': '2020-03-12'}}) mock_sailthru_purchase.return_value = MockSailthruResponse({'ok': True}) update_course_enrollment.delay(TEST_EMAIL, self.course_url, True, 'verified', course_id=self.course_id, currency='USD', message_id='cookie_bid', unit_cost=49) mock_sailthru_purchase.assert_called_with(TEST_EMAIL, [{'vars': {'course_run_id': self.course_id, 'mode': 'verified', 'upgrade_deadline_verified': '2020-03-12'}, 'title': 'Course ' + self.course_id + ' mode: verified', 'url': self.course_url, 'price': 4900, 'qty': 1, 'id': self.course_id + '-verified'}], options={'reminder_template': 'abandoned_template', 'reminder_time': '+60 minutes'}, incomplete=True, message_id='cookie_bid')
def test_sailthru_disabled(self, mock_log_error, mock_get_configuration): """Make sure nothing done and no error issued with disabled""" mock_get_configuration.return_value = {'SAILTHRU_ENABLE': False} update_course_enrollment.delay(TEST_EMAIL, self.course_url, True, 'verified') self.assertFalse(mock_log_error.called)
def test_unspecified_key(self, mock_log_error, mock_get_configuration): # Test unspecified key mock_get_configuration.return_value = {'SAILTHRU_ENABLE': True} update_course_enrollment.delay(TEST_EMAIL, self.course_url, True, 'verified', site_code='nonexistant_site') self.assertTrue(mock_log_error.called)
def process_checkout_complete( sender, order=None, user=None, request=None, # pylint: disable=unused-argument response=None, **kwargs): # pylint: disable=unused-argument """Tell Sailthru when payment done. Arguments: Parameters described at http://django-oscar.readthedocs.io/en/releases-1.1/ref/signals.html """ if not waffle.switch_is_active('sailthru_enable'): return partner = order.site.siteconfiguration.partner if not partner.enable_sailthru: return # get campaign id from cookies, or saved value in basket message_id = None if request: message_id = request.COOKIES.get('sailthru_bid') if not message_id: saved_id = BasketAttribute.objects.filter( basket=order.basket, attribute_type=get_basket_attribute_type()) if len(saved_id) > 0: message_id = saved_id[0].value_text # loop through lines in order # If multi product orders become common it may be worthwhile to pass an array of # orders to the worker in one call to save overhead, however, that would be difficult # because of the fact that there are different templates for free enroll versus paid enroll for line in order.lines.all(): # get product product = line.product # ignore everything except course seats. no support for coupons as of yet product_class_name = product.get_product_class().name if product_class_name == SEAT_PRODUCT_CLASS_NAME: price = line.line_price_excl_tax course_id = product.course_id # Tell Sailthru that the purchase is complete asynchronously update_course_enrollment.delay(order.user.email, _build_course_url(course_id), False, mode_for_seat(product), unit_cost=price, course_id=course_id, currency=order.currency, site_code=partner.short_code, message_id=message_id)
def process_basket_addition(sender, product=None, user=None, request=None, basket=None, **kwargs): # pylint: disable=unused-argument """Tell Sailthru when payment started. Arguments: Parameters described at http://django-oscar.readthedocs.io/en/releases-1.1/ref/signals.html """ if not waffle.switch_is_active('sailthru_enable'): return partner = request.site.siteconfiguration.partner if not partner.enable_sailthru: return # ignore everything except course seats. no support for coupons as of yet product_class_name = product.get_product_class().name if product_class_name == SEAT_PRODUCT_CLASS_NAME: course_id = product.course_id stock_record = product.stockrecords.first() if stock_record: price = stock_record.price_excl_tax currency = stock_record.price_currency # save Sailthru campaign ID, if there is one message_id = request.COOKIES.get('sailthru_bid') if message_id and basket: BasketAttribute.objects.update_or_create( basket=basket, attribute_type=get_basket_attribute_type(), defaults={'value_text': message_id}) # inform sailthru if there is a price. The purpose of this call is to tell Sailthru when # an item has been added to the shopping cart so that an abandoned cart message can be sent # later if the purchase is not completed. Abandoned cart support is only for purchases, not # for free enrolls if price: update_course_enrollment.delay(user.email, _build_course_url(course_id), True, mode_for_seat(product), unit_cost=price, course_id=course_id, currency=currency, site_code=partner.short_code, message_id=message_id)
def test_user_get_error(self, mock_sailthru_api_get, mock_log_error): # test error reading unenrolled list mock_sailthru_api_get.return_value = MockSailthruResponse( {}, error='error', code=43) update_course_enrollment.delay(TEST_EMAIL, self.course_url, False, 'honor', course_id=self.course_id, currency='USD', message_id='cookie_bid', unit_cost=Decimal(99)) self.assertTrue(mock_log_error.called)
def test_purchase_api_exception(self, mock_sailthru_purchase, mock_log_error): """test purchase API exception""" mock_sailthru_purchase.side_effect = SailthruClientError update_course_enrollment.delay(TEST_EMAIL, self.course_url, False, 'verified', course_id=self.course_id, currency='USD', message_id='cookie_bid', unit_cost=Decimal(99)) self.assertTrue(mock_log_error.called)
def test_user_get_error(self, mock_sailthru_api_get, mock_log_error): # test error reading unenrolled list mock_sailthru_api_get.return_value = MockSailthruResponse({}, error='error', code=43) update_course_enrollment.delay(TEST_EMAIL, self.course_url, False, 'honor', course_id=self.course_id, currency='USD', message_id='cookie_bid', unit_cost=Decimal(99)) self.assertTrue(mock_log_error.called)
def process_checkout_complete(sender, order=None, user=None, request=None, # pylint: disable=unused-argument response=None, **kwargs): # pylint: disable=unused-argument """Tell Sailthru when payment done. Arguments: Parameters described at http://django-oscar.readthedocs.io/en/releases-1.1/ref/signals.html """ if not waffle.switch_is_active('sailthru_enable'): return partner = order.site.siteconfiguration.partner if not partner.enable_sailthru: return # get campaign id from cookies, or saved value in basket message_id = None if request: message_id = request.COOKIES.get('sailthru_bid') if not message_id: saved_id = BasketAttribute.objects.filter( basket=order.basket, attribute_type=get_basket_attribute_type() ) if len(saved_id) > 0: message_id = saved_id[0].value_text # loop through lines in order # If multi product orders become common it may be worthwhile to pass an array of # orders to the worker in one call to save overhead, however, that would be difficult # because of the fact that there are different templates for free enroll versus paid enroll for line in order.lines.all(): # get product product = line.product # ignore everything except course seats. no support for coupons as of yet product_class_name = product.get_product_class().name if product_class_name == SEAT_PRODUCT_CLASS_NAME: price = line.line_price_excl_tax course_id = product.course_id # Tell Sailthru that the purchase is complete asynchronously update_course_enrollment.delay(order.user.email, _build_course_url(course_id), False, mode_for_seat(product), unit_cost=price, course_id=course_id, currency=order.currency, site_code=partner.short_code, message_id=message_id)
def test_update_course_purchase(self, mock_sailthru_api_post, mock_sailthru_api_get, mock_sailthru_purchase): """test add purchase to cart""" # create mocked Sailthru API responses mock_sailthru_api_post.return_value = MockSailthruResponse( {'ok': True}) mock_sailthru_api_get.return_value = MockSailthruResponse({ 'tags': 'tag1,tag2', 'title': 'Course title' }) mock_sailthru_purchase.return_value = MockSailthruResponse( {'ok': True}) update_course_enrollment.delay(TEST_EMAIL, self.course_url2, True, 'credit', course_id=self.course_id2, currency='USD', message_id='cookie_bid', unit_cost=49) mock_sailthru_purchase.assert_called_with( TEST_EMAIL, [{ 'vars': { 'purchase_sku': None, 'course_run_id': self.course_id2, 'mode': 'credit' }, 'title': 'Course title', 'url': self.course_url2, 'tags': 'tag1,tag2', 'price': 4900, 'qty': 1, 'id': self.course_id2 + '-credit' }], options={ 'reminder_template': 'abandoned_template', 'reminder_time': '+60 minutes' }, incomplete=True, message_id='cookie_bid')
def test_purchase_api_error(self, mock_sailthru_api_post, mock_sailthru_api_get, mock_sailthru_purchase, mock_log_error): """test purchase API error""" # create mocked Sailthru API responses mock_sailthru_api_post.return_value = MockSailthruResponse({'ok': True}) mock_sailthru_api_get.return_value = MockSailthruResponse({'vars': {'upgrade_deadline_verified': '2020-03-12'}}) mock_sailthru_purchase.return_value = MockSailthruResponse({}, error='error') update_course_enrollment.delay(TEST_EMAIL, self.course_url, False, 'verified', course_id=self.course_id, currency='USD', message_id='cookie_bid', unit_cost=Decimal(99)) self.assertTrue(mock_log_error.called)
def test_update_course_upgrade_complete_site(self, mock_sailthru_api_post, mock_sailthru_api_get, mock_sailthru_purchase): """test upgrade complete with site code""" # create mocked Sailthru API responses mock_sailthru_api_post.return_value = MockSailthruResponse( {'ok': True}) mock_sailthru_api_get.return_value = MockSailthruResponse( {'vars': { 'upgrade_deadline_verified': '2020-03-12' }}) mock_sailthru_purchase.return_value = MockSailthruResponse( {'ok': True}) # test upgrade complete with site code with patch('ecommerce_worker.configuration.test.SITE_OVERRIDES', get_configuration('TEST_SITE_OVERRIDES')): update_course_enrollment.delay(TEST_EMAIL, self.course_url, False, 'verified', course_id=self.course_id, currency='USD', message_id='cookie_bid', unit_cost=Decimal(99.01), site_code='test_site') mock_sailthru_purchase.assert_called_with( TEST_EMAIL, [{ 'vars': { 'purchase_sku': None, 'course_run_id': self.course_id, 'mode': 'verified', 'upgrade_deadline_verified': '2020-03-12' }, 'title': 'Course ' + self.course_id + ' mode: verified', 'url': self.course_url, 'price': 9901, 'qty': 1, 'id': self.course_id + '-verified' }], options={'send_template': 'site_upgrade_template'}, incomplete=False, message_id='cookie_bid')
def process_basket_addition(sender, product=None, user=None, request=None, basket=None, **kwargs): # pylint: disable=unused-argument """Tell Sailthru when payment started. Arguments: Parameters described at http://django-oscar.readthedocs.io/en/releases-1.1/ref/signals.html """ if not waffle.switch_is_active('sailthru_enable'): return partner = request.site.siteconfiguration.partner if not partner.enable_sailthru: return # ignore everything except course seats. no support for coupons as of yet product_class_name = product.get_product_class().name if product_class_name == SEAT_PRODUCT_CLASS_NAME: course_id = product.course_id stock_record = product.stockrecords.first() if stock_record: price = stock_record.price_excl_tax currency = stock_record.price_currency # save Sailthru campaign ID, if there is one message_id = request.COOKIES.get('sailthru_bid') if message_id and basket: BasketAttribute.objects.update_or_create( basket=basket, attribute_type=get_basket_attribute_type(), defaults={'value_text': message_id} ) # inform sailthru if there is a price. The purpose of this call is to tell Sailthru when # an item has been added to the shopping cart so that an abandoned cart message can be sent # later if the purchase is not completed. Abandoned cart support is only for purchases, not # for free enrolls if price: update_course_enrollment.delay(user.email, _build_course_url(course_id), True, mode_for_seat(product), unit_cost=price, course_id=course_id, currency=currency, site_code=partner.short_code, message_id=message_id)
def test_update_course_upgrade(self, mock_sailthru_api_post, mock_sailthru_api_get, mock_sailthru_purchase): """test add upgrade to cart""" # create mocked Sailthru API responses mock_sailthru_api_post.return_value = MockSailthruResponse( {'ok': True}) mock_sailthru_api_get.return_value = MockSailthruResponse( {'vars': { 'upgrade_deadline_verified': '2020-03-12' }}) mock_sailthru_purchase.return_value = MockSailthruResponse( {'ok': True}) update_course_enrollment.delay(TEST_EMAIL, self.course_url, True, 'verified', course_id=self.course_id, currency='USD', message_id='cookie_bid', unit_cost=49) mock_sailthru_purchase.assert_called_with( TEST_EMAIL, [{ 'vars': { 'purchase_sku': None, 'course_run_id': self.course_id, 'mode': 'verified', 'upgrade_deadline_verified': '2020-03-12' }, 'title': 'Course ' + self.course_id + ' mode: verified', 'url': self.course_url, 'price': 4900, 'qty': 1, 'id': self.course_id + '-verified' }], options={ 'reminder_template': 'abandoned_template', 'reminder_time': '+60 minutes' }, incomplete=True, message_id='cookie_bid')
def test_purchase_api_error(self, mock_sailthru_api_post, mock_sailthru_api_get, mock_sailthru_purchase, mock_log_error): """test purchase API error""" # create mocked Sailthru API responses mock_sailthru_api_post.return_value = MockSailthruResponse({'ok': True}) mock_sailthru_api_get.return_value = MockSailthruResponse({'vars': {'upgrade_deadline_verified': '2020-03-12'}}) mock_sailthru_purchase.return_value = MockSailthruResponse({}, error='error') update_course_enrollment.delay( TEST_EMAIL, self.course_url, False, 'verified', course_id=self.course_id, currency='USD', message_id='cookie_bid', unit_cost=Decimal(99) ) self.assertTrue(mock_log_error.called)
def test_update_course_enroll(self, mock_sailthru_api_post, mock_sailthru_api_get, mock_sailthru_purchase): """test audit enroll""" # create mocked Sailthru API responses mock_sailthru_api_post.return_value = MockSailthruResponse( {'ok': True}) mock_sailthru_api_get.return_value = MockSailthruResponse( {'vars': { 'upgrade_deadline_verified': '2020-03-12' }}) mock_sailthru_purchase.return_value = MockSailthruResponse( {'ok': True}) update_course_enrollment.delay(TEST_EMAIL, self.course_url, False, 'audit', course_id=self.course_id, currency='USD', message_id='cookie_bid', unit_cost=Decimal(0)) mock_sailthru_purchase.assert_called_with( TEST_EMAIL, [{ 'vars': { 'purchase_sku': None, 'course_run_id': self.course_id, 'mode': 'audit', 'upgrade_deadline_verified': '2020-03-12' }, 'title': 'Course ' + self.course_id + ' mode: audit', 'url': self.course_url, 'price': 0, 'qty': 1, 'id': self.course_id + '-audit' }], options={'send_template': 'enroll_template'}, incomplete=False, message_id='cookie_bid')
def test_update_course_enroll_skip(self, mock_sailthru_api_post, mock_sailthru_api_get, mock_sailthru_purchase, mock_get_configuration): """test audit enroll with configured cost = 0""" config = get_configuration('SAILTHRU') config['SAILTHRU_MINIMUM_COST'] = 0 mock_get_configuration.return_value = config # create mocked Sailthru API responses mock_sailthru_api_post.return_value = MockSailthruResponse({'ok': True}) mock_sailthru_api_get.return_value = MockSailthruResponse({'vars': {'upgrade_deadline_verified': '2020-03-12'}}) mock_sailthru_purchase.return_value = MockSailthruResponse({'ok': True}) update_course_enrollment.delay(TEST_EMAIL, self.course_url, False, 'audit', course_id=self.course_id, currency='USD', message_id='cookie_bid', unit_cost=Decimal(0)) mock_sailthru_purchase.assert_not_called()
def process_checkout_complete(sender, order=None, user=None, request=None, # pylint: disable=unused-argument response=None, **kwargs): # pylint: disable=unused-argument """Tell Sailthru when payment done. Arguments: Parameters described at http://django-oscar.readthedocs.io/en/releases-1.1/ref/signals.html """ if not waffle.switch_is_active('sailthru_enable'): return message_id = None if request: message_id = request.COOKIES.get('sailthru_bid') # loop through lines in order # If multi product orders become common it may be worthwhile to pass an array of # orders to the worker in one call to save overhead, however, that would be difficult # because of the fact that there are different templates for free enroll versus paid enroll for line in order.lines.all(): # get product product = line.product # get price price = line.line_price_excl_tax course_id = product.course_id # figure out course url course_url = _build_course_url(course_id) # pass event to ecommerce_worker.sailthru.v1.tasks to handle asynchronously update_course_enrollment.delay(order.user.email, course_url, False, mode_for_seat(product), unit_cost=price, course_id=course_id, currency=order.currency, site_code=order.site.siteconfiguration.partner.short_code, message_id=message_id)