def test_valid_payment_segment_logging(self, mock_track): """ Verify the "Payment Info Entered" Segment event is fired after payment info is validated """ basket = create_basket(owner=self.user, site=self.site) mixin = EdxOrderPlacementMixin() mixin.payment_processor = DummyProcessor(self.site) properties = {'checkout_id': basket.order_number} user_tracking_id, lms_client_id, lms_ip = parse_tracking_context( self.user) context = { 'ip': lms_ip, 'Google Analytics': { 'clientId': lms_client_id } } mixin.handle_payment({}, basket) # ensure that the only two Segment events fired are 'Product Added' and 'Payment Info Entered' self.assertEqual(mock_track.call_count, 2) mock_track.assert_called_with(user_tracking_id, 'Payment Info Entered', properties, context=context)
def test_create_assignments_for_multi_use_per_customer(self, __): """ Verify the `create_assignments_for_multi_use_per_customer` works as expected for `MULTI_USE_PER_CUSTOMER`. """ coupon_max_global_applications = 10 enterprise_offer = EnterpriseOfferFactory( max_global_applications=coupon_max_global_applications) voucher = VoucherFactory(usage=Voucher.MULTI_USE_PER_CUSTOMER) voucher.offers.add(enterprise_offer) basket = create_basket(owner=self.user, site=self.site) basket.vouchers.add(voucher) order = create_order(user=self.user, basket=basket) assert OfferAssignment.objects.all().count() == 0 EdxOrderPlacementMixin().create_assignments_for_multi_use_per_customer( order) EdxOrderPlacementMixin().update_assigned_voucher_offer_assignment( order) assert OfferAssignment.objects.all().count( ) == coupon_max_global_applications assert OfferAssignment.objects.filter( offer=enterprise_offer, code=voucher.code, user_email=basket.owner.email, status=OFFER_ASSIGNED).count() == 9 assert OfferAssignment.objects.filter( offer=enterprise_offer, code=voucher.code, user_email=basket.owner.email, status=OFFER_REDEEMED).count() == 1
def test_order_number_collision(self, _mock_track): """ Verify that an attempt to create an order with the same number as an existing order causes an exception to be raised. """ order_placement_mixin = EdxOrderPlacementMixin() basket = self.order.basket shipping_method = NoShippingRequired() shipping_charge = shipping_method.calculate(basket) order_total = OrderTotalCalculator().calculate(basket, shipping_charge) with self.assertRaises(ValueError): order_placement_mixin.handle_order_placement( self.order.number, self.user, basket, None, shipping_method, shipping_charge, None, order_total, )
def test_handle_payment_logging(self, __): """ Ensure that we emit a log entry upon receipt of a payment notification, and create Source and PaymentEvent objects. """ basket = create_basket(owner=self.user, site=self.site) mixin = EdxOrderPlacementMixin() mixin.payment_processor = DummyProcessor(self.site) processor_name = DummyProcessor.NAME total = basket.total_incl_tax reference = basket.id with LogCapture(LOGGER_NAME) as logger: mixin.handle_payment({}, basket) logger.check_present(( LOGGER_NAME, 'INFO', 'payment_received: amount="{}", basket_id="{}", currency="{}", ' 'processor_name="{}", reference="{}", user_id="{}"'.format( total, basket.id, basket.currency, processor_name, reference, self.user.id))) # pylint: disable=protected-access # Validate a payment Source was created source_type = SourceType.objects.get(code=processor_name) label = self.user.username self.assert_basket_matches_source(basket, mixin._payment_sources[-1], source_type, reference, label) # Validate the PaymentEvent was created paid_type = PaymentEventType.objects.get(code='paid') self.assert_valid_payment_event_fields(mixin._payment_events[-1], total, paid_type, processor_name, reference)
def test_create_offer_assignments_for_updated_max_uses(self, __): """ Verify the `create_assignments_for_multi_use_per_customer` works as expected for `MULTI_USE_PER_CUSTOMER` when `max_global_applications` is updated for existing voucher. """ coupon_max_global_applications = 1 enterprise_offer = EnterpriseOfferFactory( max_global_applications=coupon_max_global_applications) voucher = VoucherFactory(usage=Voucher.MULTI_USE_PER_CUSTOMER) voucher.offers.add(enterprise_offer) basket = create_basket(owner=self.user, site=self.site) basket.vouchers.add(voucher) order = create_order(user=self.user, basket=basket) assert OfferAssignment.objects.all().count() == 0 EdxOrderPlacementMixin().create_assignments_for_multi_use_per_customer( order) EdxOrderPlacementMixin().update_assigned_voucher_offer_assignment( order) assert OfferAssignment.objects.all().count( ) == coupon_max_global_applications assert OfferAssignment.objects.filter( offer=enterprise_offer, code=voucher.code, user_email=basket.owner.email, status=OFFER_REDEEMED).count() == 1 # update max_global_applications coupon_new_max_global_applications = 5 enterprise_offer.max_global_applications = coupon_new_max_global_applications enterprise_offer.save() assert voucher.enterprise_offer.max_global_applications == coupon_new_max_global_applications EdxOrderPlacementMixin().create_assignments_for_multi_use_per_customer( order) assert OfferAssignment.objects.all().count( ) == coupon_new_max_global_applications assert OfferAssignment.objects.filter( offer=enterprise_offer, code=voucher.code, user_email=basket.owner.email, status=OFFER_ASSIGNED).count() == 4 assert OfferAssignment.objects.filter( offer=enterprise_offer, code=voucher.code, user_email=basket.owner.email, status=OFFER_REDEEMED).count() == 1 # call once again to verify nothing is created because all available slots are assigned EdxOrderPlacementMixin().create_assignments_for_multi_use_per_customer( order) assert OfferAssignment.objects.all().count( ) == coupon_new_max_global_applications
def test_handle_successful_order_no_email_opt_in(self, _): """ Verify that the post checkout defaults email_opt_in to false. """ with mock.patch('ecommerce.extensions.checkout.mixins.post_checkout.send') as mock_send: mixin = EdxOrderPlacementMixin() mixin.handle_successful_order(self.order) send_arguments = {'sender': mixin, 'order': self.order, 'request': None, 'email_opt_in': False} mock_send.assert_called_once_with(**send_arguments)
def test_payment_not_accepted_segment_logging(self, mock_track): """ Verify if the payment is not accepted, we still log the processor response """ tracking_context = { 'ga_client_id': 'test-client-id', 'lms_user_id': 'test-user-id', 'lms_ip': '127.0.0.1' } self.user.tracking_context = tracking_context self.user.save() basket = create_basket(owner=self.user, site=self.site) mixin = EdxOrderPlacementMixin() mixin.payment_processor = DummyProcessor(self.site) user_tracking_id, ga_client_id, lms_ip = parse_tracking_context( self.user) context = { 'ip': lms_ip, 'Google Analytics': { 'clientId': ga_client_id }, 'page': { 'url': 'https://testserver.fake/' }, } with self.assertRaises(Exception): mixin.handle_payment({}, basket) # Verify the correct events are fired to Segment calls = [] properties = translate_basket_line_for_segment(basket.lines.first()) properties['cart_id'] = basket.id calls.append( mock.call(user_tracking_id, 'Product Added', properties, context=context)) properties = { 'basket_id': basket.id, 'payment_error': 'Exception', 'success': False, 'processor_name': DummyProcessor.NAME, } calls.append( mock.call(user_tracking_id, 'Payment Processor Response', properties, context=context)) mock_track.assert_has_calls(calls)
def test_non_free_basket_order(self, __): """ Verify an error is raised for non-free basket. """ basket = create_basket(empty=True) basket.add_product(ProductFactory(stockrecords__price_excl_tax=10)) with self.assertRaises(BasketNotFreeError): EdxOrderPlacementMixin().place_free_order(basket)
def test_handle_post_order_for_bulk_purchase(self, __): """ Ensure that the bulk purchase order is linked to the provided business client when the method `handle_post_order` is invoked. """ toggle_switch(ENROLLMENT_CODE_SWITCH, True) course = CourseFactory(partner=self.partner) course.create_or_update_seat('verified', True, 50, 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, quantity=1) order = create_order(number=1, basket=basket, user=user) request_data = { 'organization': 'Dummy Business Client', PURCHASER_BEHALF_ATTRIBUTE: 'False', } # Manually add organization and purchaser attributes on the basket for testing basket_add_organization_attribute(basket, request_data) EdxOrderPlacementMixin().handle_post_order(order) # Now verify that a new business client has been created in current # order is now linked with that client through Invoice model. business_client = BusinessClient.objects.get( name=request_data['organization']) assert Invoice.objects.get( order=order).business_client == business_client
def test_order_no_lms_user_id(self, mock_track): """ Ensure that expected values are substituted when no LMS user id was available. """ tracking_context = { 'ga_client_id': 'test-client-id', 'lms_user_id': 'test-user-id', 'lms_ip': '127.0.0.1' } self.user.tracking_context = tracking_context self.user.lms_user_id = None self.user.save() EdxOrderPlacementMixin().handle_successful_order(self.order) # ensure event is being tracked self.assertTrue(mock_track.called) # ensure event data is correct self.assert_correct_event( mock_track, self.order, ECOM_TRACKING_ID_FMT.format(self.user.id), tracking_context['ga_client_id'], tracking_context['lms_ip'], self.order.number, self.order.currency, self.order.user.email, self.order.total_excl_tax, self.order. total_excl_tax, # value for revenue field is same as total. check_traits=True, )
def test_handle_payment_logging(self, __): """ Ensure that we emit a log entry upon receipt of a payment notification. """ amount = Decimal('9.99') basket_id = 'test-basket-id' currency = 'USD' processor_name = 'test-processor-name' reference = 'test-reference' user_id = '1' mock_source = Mock(currency=currency) mock_payment_event = Mock(amount=amount, processor_name=processor_name, reference=reference) mock_handle_processor_response = Mock( return_value=(mock_source, mock_payment_event)) mock_payment_processor = Mock( handle_processor_response=mock_handle_processor_response) with patch( 'ecommerce.extensions.checkout.mixins.EdxOrderPlacementMixin.payment_processor', mock_payment_processor): mock_basket = Mock(id=basket_id, owner=Mock(id=user_id)) with LogCapture(LOGGER_NAME) as l: EdxOrderPlacementMixin().handle_payment(Mock(), mock_basket) l.check(( LOGGER_NAME, 'INFO', 'payment_received: amount="{}", basket_id="{}", currency="{}", ' 'processor_name="{}", reference="{}", user_id="{}"'.format( amount, basket_id, currency, processor_name, reference, user_id)))
def test_handle_successful_order(self, mock_track): """ Ensure that tracking events are fired with correct content when order placement event handling is invoked. """ tracking_context = { 'lms_user_id': 'test-user-id', 'lms_client_id': 'test-client-id', 'lms_ip': '127.0.0.1' } self.user.tracking_context = tracking_context self.user.save() with LogCapture(LOGGER_NAME) as l: EdxOrderPlacementMixin().handle_successful_order(self.order) # ensure event is being tracked self.assertTrue(mock_track.called) # ensure event data is correct self.assert_correct_event(mock_track, self.order, tracking_context['lms_user_id'], tracking_context['lms_client_id'], tracking_context['lms_ip'], self.order.number, self.order.currency, self.order.total_excl_tax) l.check(( LOGGER_NAME, 'INFO', 'order_placed: amount="{}", basket_id="{}", contains_coupon="{}", currency="{}",' ' order_number="{}", user_id="{}"'.format( self.order.total_excl_tax, self.order.basket.id, self.order.contains_coupon, self.order.currency, self.order.number, self.order.user.id)))
def test_handle_successful_free_order(self, mock_track): """Verify that tracking events are not emitted for free orders.""" order = self.create_order(free=True, status=ORDER.OPEN) EdxOrderPlacementMixin().handle_successful_order(order) # Verify that no event was emitted. self.assertFalse(mock_track.called)
def test_handle_successful_async_order(self, __): """ Verify that a Waffle Sample can be used to control async order fulfillment. """ sample, created = Sample.objects.get_or_create( name='async_order_fulfillment', defaults={ 'percent': 100.0, 'note': 'Determines what percentage of orders are fulfilled asynchronously.', }) if not created: sample.percent = 100.0 sample.save() with mock.patch( 'ecommerce.extensions.checkout.mixins.fulfill_order.delay' ) as mock_delay: EdxOrderPlacementMixin().handle_successful_order(self.order) mock_delay.assert_called_once_with( self.order.number, site_code=self.partner.short_code, email_opt_in=False)
def test_handle_post_order_for_seat_purchase(self, __): """ Ensure that the single seat purchase order is not linked any business client when the method `handle_post_order` is invoked. """ toggle_switch(ENROLLMENT_CODE_SWITCH, False) course = CourseFactory(partner=self.partner) verified_product = course.create_or_update_seat('verified', True, 50) user = UserFactory() basket = BasketFactory(owner=user, site=self.site) basket.add_product(verified_product, quantity=1) order = create_order(number=1, basket=basket, user=user) request_data = { 'organization': 'Dummy Business Client', PURCHASER_BEHALF_ATTRIBUTE: 'False', } # Manually add organization and purchaser attributes on the basket for testing basket_add_organization_attribute(basket, request_data) EdxOrderPlacementMixin().handle_post_order(order) # Now verify that the single seat order is not linked to business # client by checking that there is no record for BusinessClient. assert not BusinessClient.objects.all()
def test_valid_payment_segment_logging(self, mock_track): """ Verify the "Payment Info Entered" Segment event is fired after payment info is validated """ tracking_context = {'ga_client_id': 'test-client-id', 'lms_user_id': 'test-user-id', 'lms_ip': '127.0.0.1'} self.user.tracking_context = tracking_context self.user.save() basket = create_basket(owner=self.user, site=self.site) mixin = EdxOrderPlacementMixin() mixin.payment_processor = DummyProcessor(self.site) user_tracking_id, ga_client_id, lms_ip = parse_tracking_context(self.user) context = { 'ip': lms_ip, 'Google Analytics': { 'clientId': ga_client_id }, 'page': { 'url': 'https://testserver.fake/' }, } mixin.handle_payment({}, basket) # Verify the correct events are fired to Segment calls = [] properties = translate_basket_line_for_segment(basket.lines.first()) properties['cart_id'] = basket.id calls.append(mock.call(user_tracking_id, 'Product Added', properties, context=context)) properties = { 'checkout_id': basket.order_number, 'step': 1, 'payment_method': 'Visa | ' + DummyProcessor.NAME, } calls.append(mock.call(user_tracking_id, 'Checkout Step Completed', properties, context=context)) properties['step'] = 2 calls.append(mock.call(user_tracking_id, 'Checkout Step Viewed', properties, context=context)) calls.append(mock.call(user_tracking_id, 'Checkout Step Completed', properties, context=context)) properties = {'checkout_id': basket.order_number} calls.append(mock.call(user_tracking_id, 'Payment Info Entered', properties, context=context)) mock_track.assert_has_calls(calls)
def test_handle_successful_order_no_segment_key(self, mock_track): """ Ensure that tracking events do not fire when there is no Segment key configured. """ EdxOrderPlacementMixin().handle_successful_order(self.order) # ensure no event was fired self.assertFalse(mock_track.called)
def test_place_free_order(self, __): """ Verify an order is placed and the basket is submitted. """ basket = create_basket(empty=True) 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 test_duplicate_order_attempt_logging(self): """ Verify that attempts at creation of a duplicate order are logged correctly """ prior_order = create_order() dummy_request = RequestFactory(SERVER_NAME='testserver.fake').get('') dummy_mixin = EdxOrderPlacementMixin() dummy_mixin.payment_processor = Cybersource(self.site) with LogCapture(self.DUPLICATE_ORDER_LOGGER_NAME) as lc: with self.assertRaises(ValueError): dummy_mixin.create_order(dummy_request, prior_order.basket, None) lc.check((self.DUPLICATE_ORDER_LOGGER_NAME, 'ERROR', self.get_duplicate_order_error_message( payment_processor='Cybersource', order=prior_order)), )
def test_handle_successful_free_order(self, mock_track): """Verify that tracking events are not emitted for free orders.""" order = self.create_order(free=True, status=ORDER.OPEN) EdxOrderPlacementMixin().handle_successful_order(order) # Ensure that only 'Product Added' event is emitted (in order creation) and not 'Order Completion' event. self.assertEqual(mock_track.call_count, 1) event_name = mock_track.call_args[0][1] self.assertEqual(event_name, 'Product Added')
def test_handle_payment_logging(self, __): """ Ensure that we emit a log entry upon receipt of a payment notification, and create Source and PaymentEvent objects. """ user = factories.UserFactory() basket = factories.create_basket() basket.owner = user basket.save() mixin = EdxOrderPlacementMixin() mixin.payment_processor = DummyProcessor(self.site) processor_name = DummyProcessor.NAME total = basket.total_incl_tax reference = basket.id with LogCapture(LOGGER_NAME) as l: mixin.handle_payment({}, basket) l.check( ( LOGGER_NAME, 'INFO', 'payment_received: amount="{}", basket_id="{}", currency="{}", ' 'processor_name="{}", reference="{}", user_id="{}"'.format( total, basket.id, basket.currency, processor_name, reference, user.id ) ) ) # pylint: disable=protected-access # Validate a payment Source was created source_type = SourceType.objects.get(code=processor_name) label = user.username self.assert_basket_matches_source(basket, mixin._payment_sources[-1], source_type, reference, label) # Validate the PaymentEvent was created paid_type = PaymentEventType.objects.get(code='paid') self.assert_valid_payment_event_fields(mixin._payment_events[-1], total, paid_type, processor_name, reference)
def test_handle_successful_order_with_email_opt_in(self, expected_opt_in, _): """ Verify that the post checkout sets email_opt_in if it is given. """ BasketAttribute.objects.get_or_create( basket=self.order.basket, attribute_type=BasketAttributeType.objects.get(name=EMAIL_OPT_IN_ATTRIBUTE), value_text=expected_opt_in, ) with mock.patch('ecommerce.extensions.checkout.mixins.post_checkout.send') as mock_send: mixin = EdxOrderPlacementMixin() mixin.handle_successful_order(self.order) send_arguments = { 'sender': mixin, 'order': self.order, 'request': None, 'email_opt_in': expected_opt_in, } mock_send.assert_called_once_with(**send_arguments)
def test_handle_successful_order_segment_error(self, mock_track): """ Ensure that exceptions raised while emitting tracking events are logged, but do not otherwise interrupt program flow. """ with patch('ecommerce.extensions.analytics.utils.logger.exception') as mock_log_exc: mock_track.side_effect = Exception("clunk") EdxOrderPlacementMixin().handle_successful_order(self.order) # ensure that analytics.track was called, but the exception was caught self.assertTrue(mock_track.called) # ensure we logged a warning. self.assertTrue(mock_log_exc.called_with("Failed to emit tracking event upon order placement."))
def test_handle_successful_order_no_context(self, mock_track): """ Ensure that expected values are substituted when no tracking_context was available. """ EdxOrderPlacementMixin().handle_successful_order(self.order) # ensure event is being tracked self.assertTrue(mock_track.called) # ensure event data is correct self.assert_correct_event(mock_track, self.order, 'ecommerce-{}'.format(self.user.id), None, None, self.order.number, self.order.currency, self.order.total_excl_tax)
def test_send_confirmation_message(self, __): """ Verify the send confirmation message override functions as expected """ request = RequestFactory() user = self.create_user() user.email = '*****@*****.**' request.user = user site_from_email = '*****@*****.**' site_configuration = SiteConfigurationFactory(partner__name='Tester', from_email=site_from_email) request.site = site_configuration.site order = factories.create_order() order.user = user mixin = EdxOrderPlacementMixin() mixin.request = request # Happy path mixin.send_confirmation_message(order, 'ORDER_PLACED', request.site) self.assertEqual(mail.outbox[0].from_email, site_from_email) mail.outbox = [] # Invalid code path (graceful exit) mixin.send_confirmation_message(order, 'INVALID_CODE', request.site) self.assertEqual(len(mail.outbox), 0) # Invalid messages container path (graceful exit) with patch('ecommerce.extensions.checkout.mixins.CommunicationEventType.objects.get') as mock_get: mock_event_type = Mock() mock_event_type.get_messages.return_value = {} mock_get.return_value = mock_event_type mixin.send_confirmation_message(order, 'ORDER_PLACED', request.site) self.assertEqual(len(mail.outbox), 0) mock_event_type.get_messages.return_value = {'body': None} mock_get.return_value = mock_event_type mixin.send_confirmation_message(order, 'ORDER_PLACED', request.site) self.assertEqual(len(mail.outbox), 0)
def test_update_assigned_voucher_offer_assignment(self, __): """ Verify the "update_assigned_voucher_offer_assignment" works as expected. """ enterprise_offer = EnterpriseOfferFactory() voucher = VoucherFactory() voucher.offers.add(enterprise_offer) basket = create_basket(owner=self.user, site=self.site) basket.vouchers.add(voucher) order = create_order(user=self.user, basket=basket) voucher_application = VoucherApplication.objects.create(voucher=voucher, user=self.user, order=order) offer_assignment = OfferAssignmentFactory(offer=enterprise_offer, code=voucher.code, user_email=self.user.email) EdxOrderPlacementMixin().update_assigned_voucher_offer_assignment(order) offer_assignment = OfferAssignment.objects.get(id=offer_assignment.id) assert offer_assignment.status == OFFER_REDEEMED assert offer_assignment.voucher_application == voucher_application
def test_update_assigned_voucher_offer_assignment(self, __): """ Verify the "update_assigned_voucher_offer_assignment" works as expected. """ enterprise_offer = EnterpriseOfferFactory() voucher = VoucherFactory() voucher.offers.add(enterprise_offer) basket = create_basket(owner=self.user, site=self.site) basket.vouchers.add(voucher) order = create_order(user=self.user, basket=basket) voucher_application = VoucherApplication.objects.create( voucher=voucher, user=self.user, order=order) offer_assignment = OfferAssignmentFactory(offer=enterprise_offer, code=voucher.code, user_email=self.user.email) # create nudge email templates and subscription records for email_type in (DAY3, DAY10, DAY19): nudge_email_template = CodeAssignmentNudgeEmailTemplatesFactory( email_type=email_type) nudge_email = CodeAssignmentNudgeEmailsFactory( email_template=nudge_email_template, user_email=self.user.email, code=voucher.code) # verify subscription is active assert nudge_email.is_subscribed EdxOrderPlacementMixin().update_assigned_voucher_offer_assignment( order) offer_assignment = OfferAssignment.objects.get(id=offer_assignment.id) assert offer_assignment.status == OFFER_REDEEMED assert offer_assignment.voucher_application == voucher_application # verify that nudge emails subscriptions are inactive assert CodeAssignmentNudgeEmails.objects.filter( is_subscribed=True).count() == 0 assert CodeAssignmentNudgeEmails.objects.filter( code__in=[voucher.code], user_email__in=[self.user.email], is_subscribed=False).count() == 3
def test_handle_successful_order_no_context(self, mock_track): """ Ensure that expected values are substituted when no tracking_context was available. """ EdxOrderPlacementMixin().handle_successful_order(self.order) # ensure event is being tracked self.assertTrue(mock_track.called) # ensure event data is correct self.assert_correct_event( mock_track, self.order, ECOM_TRACKING_ID_FMT.format(self.user.id), None, None, self.order.number, self.order.currency, self.order.user.email, self.order.total_excl_tax, self.order.total_excl_tax # value for revenue field is same as total. )
def handle(self, *args, **options): site_id = options.get('site_id') try: site = Site.objects.get(id=site_id) except Site.DoesNotExist: logger.exception('Site id %s does not exist', site_id) raise Exception try: site_configurations = SiteConfiguration.objects.get(site=site) configuration_helpers = site_configurations.edly_client_theme_branding_settings voucher_api_url = configuration_helpers.get( 'LUMSXPAY_VOUCHER_API_URL') if not voucher_api_url: logger.exception( 'Cron Job of Update Payment Statuses is canceled due to no ' 'LUMSXPAY_VOUCHER_API_URL in client theme branding') raise Exception except: logger.exception( 'Site Configurations with side id %s does not exist', site_id) raise Exception try: unpaid_challan_baskets = BasketChallanVoucher.objects.filter( is_paid=False) except: logger.exception( 'could not fetch the unpaid challan baskets from Database') raise Exception headers = { "Authorization": configuration_helpers.get('PAYMENT_AUTHORIZATION_KEY'), "Content-Type": "application/json" } paid_vouchers = [] unpaid_vouchers = unpaid_challan_baskets.values_list('voucher_number', flat=True) if unpaid_challan_baskets: for unpaid_vouchers_lst in list( self.equal_divided_chunks(list(unpaid_vouchers), self.VOUCHERS_PER_REQUEST)): unpaid_vouchers_str = ','.join(unpaid_vouchers_lst) url = '{}/{}'.format(voucher_api_url, unpaid_vouchers_str) response = requests.get(url, headers=headers) if response.status_code == 200: voucher_details = response.json() voucher_data = voucher_details['data'] if not isinstance(voucher_details['data'], list): voucher_data = [voucher_details['data']] for voucher in voucher_data: if voucher['paid_status'].lower() == 'paid': paid_vouchers.append(voucher['voucher_id']) else: logger.info('VOUCHER API doesnot return 200 OK') return else: logger.info('No unpaid voucher found for update payment status') return if not paid_vouchers: logger.info('No voucher paid so exiting the job') return unpaid_basket_ids = unpaid_challan_baskets.filter( voucher_number__in=paid_vouchers).values_list('basket_id', flat=True) paid_baskets = Basket.objects.filter(id__in=unpaid_basket_ids, status=Basket.OPEN) if not paid_baskets: logger.info( 'ERROR: Basket corresponding to voucher does not exist') raise Exception for basket in paid_baskets: shipping_method = NoShippingRequired() shipping_charge = shipping_method.calculate(basket) basket.strategy = DefaultStrategy() order_total = OrderTotalCalculator().calculate( basket, shipping_charge) user = basket.owner billing_address = None request = RequestFactory() request.site = site request.user = user request.site.siteconfiguration = site_configurations set_thread_variable('request', request) order = EdxOrderPlacementMixin().handle_order_placement( order_number=basket.order_number, user=user, basket=basket, shipping_address=None, shipping_method=shipping_method, shipping_charge=shipping_charge, billing_address=billing_address, order_total=order_total, request=request) EdxOrderPlacementMixin().handle_post_order(order) challan_voucher_basket = BasketChallanVoucher.objects.filter( basket_id=basket.id) if len(challan_voucher_basket) > 1: logger.info( 'more than one basket exist with same id in challan table.' ) elif challan_voucher_basket: challan_voucher_basket.update(is_paid=True) logger.info( 'Successfully finished the cron job for updating the order payment' ) return
def test_send_confirmation_message(self, __): """ Verify the send confirmation message override functions as expected """ request = RequestFactory() user = self.create_user() user.email = '*****@*****.**' request.user = user site_from_email = '*****@*****.**' site_configuration = SiteConfigurationFactory( partner__name='Tester', from_email=site_from_email) request.site = site_configuration.site order = factories.create_order() order.user = user mixin = EdxOrderPlacementMixin() mixin.request = request # Happy path mixin.send_confirmation_message(order, 'ORDER_PLACED', request.site) self.assertEqual(mail.outbox[0].from_email, site_from_email) mail.outbox = [] # Invalid code path (graceful exit) mixin.send_confirmation_message(order, 'INVALID_CODE', request.site) self.assertEqual(len(mail.outbox), 0) # Invalid messages container path (graceful exit) with patch( 'ecommerce.extensions.checkout.mixins.CommunicationEventType.objects.get' ) as mock_get: mock_event_type = Mock() mock_event_type.get_messages.return_value = {} mock_get.return_value = mock_event_type mixin.send_confirmation_message(order, 'ORDER_PLACED', request.site) self.assertEqual(len(mail.outbox), 0) mock_event_type.get_messages.return_value = {'body': None} mock_get.return_value = mock_event_type mixin.send_confirmation_message(order, 'ORDER_PLACED', request.site) self.assertEqual(len(mail.outbox), 0)