class UpdateEffectiveContractDiscountTests(TestCase):
    """
    Tests the enrollment code creation command.
    """

    def setUp(self):
        """
        Create test data.
        """
        super(UpdateEffectiveContractDiscountTests, self).setUp()

        # Set up orders with a enterprise_customer
        self.enterprise_customer_uuid = '123e4567-e89b-12d3-a456-426655440000'
        self.unit_price = 100
        self.condition = ManualEnrollmentOrderDiscountConditionFactory(
            enterprise_customer_uuid=self.enterprise_customer_uuid
        )
        self.offer = ConditionalOfferFactory(condition=self.condition, id=9999)
        self.order = OrderFactory()
        self.order_discount = OrderDiscountFactory(offer_id=self.offer.id, order=self.order)
        self.line = OrderLineFactory(order=self.order, unit_price_excl_tax=self.unit_price)
        self.line.save()
        self.order_discount = OrderDiscountFactory(offer_id=self.offer.id, order=self.order)
        self.order.save()
        self.offer.save()
        self.condition.save()

    def test_discount_update(self):
        discount_percentage = 20
        call_command(
            'update_effective_contract_discount',
            '--enterprise-customer={}'.format(self.enterprise_customer_uuid),
            '--discount-percentage={}'.format(discount_percentage)
        )
        assert self.line.order == self.order
    def test_convert_course(self, initial_cert_type, direction, new_cert_type):
        """Verify that an honor course can be converted to audit correctly."""
        course = CourseFactory(partner=self.partner)
        seat_to_convert = course.create_or_update_seat(initial_cert_type, False, 0)
        stock_record = StockRecord.objects.get(product=seat_to_convert)
        order_line = OrderLineFactory(stockrecord=stock_record, product=seat_to_convert, partner_sku='test_sku')

        old_stock_record_sku = stock_record.partner_sku
        old_order_line_sku = order_line.partner_sku

        # Mock the LMS call
        with mock.patch.object(LMSPublisher, 'publish') as mock_publish:
            mock_publish.return_value = True
            call_command('convert_course', course.id, commit=True, direction=direction, partner=self.partner.code)

        # Calling refresh_from_db doesn't seem to update the product's attributes
        seat_to_convert = Product.objects.get(pk=seat_to_convert.pk)
        stock_record.refresh_from_db()
        order_line.refresh_from_db()

        self.assertEqual(getattr(seat_to_convert.attr, 'certificate_type', ''), new_cert_type)

        if new_cert_type == '':
            self.assertNotIn('with honor certificate', seat_to_convert.title)
        else:
            self.assertIn(' with honor certificate', seat_to_convert.title)

        # Verify that partner SKUs are correctly updated
        self.assertNotEqual(old_stock_record_sku, stock_record.partner_sku)
        self.assertNotEqual(old_order_line_sku, order_line.partner_sku)
        self.assertEqual(order_line.partner_sku, stock_record.partner_sku)

        self.assertTrue(mock_publish.called)
Ejemplo n.º 3
0
    def use_voucher(self,
                    order_num,
                    voucher,
                    user,
                    add_entitlement=False,
                    product=None):
        """
        Mark voucher as used by provided users

        Args:
            order_num (string): Order number
            voucher (Voucher): voucher to be marked as used
            users (list): list of users
        """
        order = OrderFactory(number=order_num)
        if add_entitlement:
            order_line = OrderLineFactory(product=self.entitlement,
                                          partner_sku=self.partner_sku)
            order.lines.add(order_line)
        product = product if product else self.verified_seat
        order_line = OrderLineFactory(product=product,
                                      partner_sku=self.partner_sku)
        order.lines.add(order_line)
        voucher.record_usage(order, user)
        voucher.offers.first().record_usage(discount={
            'freq': 1,
            'discount': 1
        })
Ejemplo n.º 4
0
    def test_generate_coupon_report_for_query_coupon_with_multi_line_order(
            self):
        """
        Test that coupon report for a query coupon that was used on multi-line order
        contains ids from all courses in that order.
        """
        course1 = CourseFactory()
        course2 = CourseFactory()
        order = OrderFactory(number='TESTORDER')
        order.lines.add(
            OrderLineFactory(product=course1.create_or_update_seat(
                'verified', False, 101),
                             partner_sku=self.partner_sku))
        order.lines.add(
            OrderLineFactory(product=course2.create_or_update_seat(
                'verified', False, 110),
                             partner_sku=self.partner_sku))
        query_coupon = self.create_catalog_coupon(catalog_query='*:*')
        voucher = query_coupon.attr.coupon_vouchers.vouchers.first()
        voucher.record_usage(order, self.user)
        field_names, rows = generate_coupon_report(
            [query_coupon.attr.coupon_vouchers])

        expected_redemed_course_ids = '{}, {}'.format(course1.id, course2.id)
        self.assertEqual(rows[-1]['Redeemed For Course IDs'],
                         expected_redemed_course_ids)
        self.assertEqual(rows[-1].get('Redeemed For Course ID'), None)
        self.assertIn('Redeemed For Course ID', field_names)
        self.assertIn('Redeemed For Course IDs', field_names)
Ejemplo n.º 5
0
    def test_shipping_status(self):
        order = OrderFactory()

        line_1 = OrderLineFactory(order=order,
                                  partner_sku='SKU1234',
                                  quantity=2)
        line_2 = OrderLineFactory(order=order,
                                  partner_sku='SKU5678',
                                  quantity=1)
        self.assertEqual(order.shipping_status, '')

        event_1 = ShippingEventFactory(order=order, event_type__name='Shipped')
        event_2 = ShippingEventFactory(order=order,
                                       event_type__name='Returned')

        # Default status
        self.assertEqual(order.shipping_status, _('In progress'))

        # Set first line to shipped
        event_1.line_quantities.create(line=line_1, quantity=2)
        self.assertEqual(order.shipping_status, _('In progress'))

        # Set first line to returned
        event_2.line_quantities.create(line=line_1, quantity=2)
        self.assertEqual(order.shipping_status, _('In progress'))

        # Set second line to shipped
        event_1.line_quantities.create(line=line_2, quantity=1)
        self.assertEqual(order.shipping_status, _('Shipped'))

        # Set second line to returned
        event_2.line_quantities.create(line=line_2, quantity=1)
        self.assertEqual(order.shipping_status, _('Returned'))
Ejemplo n.º 6
0
    def setUp(self):
        # Timestamp in the middle of the time window
        time_delta = (DEFAULT_START_DELTA_TIME + DEFAULT_END_DELTA_TIME) / 2
        self.timestamp = datetime.datetime.now(pytz.utc) - datetime.timedelta(minutes=time_delta)

        self.payevent, __ = PaymentEventType.objects.get_or_create(name=PaymentEventTypeName.PAID)
        self.refundevent, __ = PaymentEventType.objects.get_or_create(name=PaymentEventTypeName.REFUNDED)
        self.seat_product_class, __ = ProductClass.objects.get_or_create(name=SEAT_PRODUCT_CLASS_NAME)
        self.order = OrderFactory(total_incl_tax=90, date_placed=self.timestamp)
        self.product = ProductFactory(product_class=self.seat_product_class, categories=None)
        self.line = OrderLineFactory(order=self.order, product=self.product, partner_sku='test_sku')
        self.line.save()
        self.product.save()
        self.order.save()
Ejemplo n.º 7
0
    def test_threshold(self):
        """Test verify_transactions only fails if there are too many anomolies"""
        for i in range(3):
            # Create some "good" orders w/ payments
            order = OrderFactory(total_incl_tax=50 + i,
                                 date_placed=self.timestamp)
            line = OrderLineFactory(order=order,
                                    product=self.product,
                                    partner_sku='test_sku')
            payment = PaymentEventFactory(order=order,
                                          amount=50 + i,
                                          event_type_id=self.payevent.id,
                                          date_created=self.timestamp)
            payment.save()
            line.save()
            order.save()

        # self.order fixture should still have no payment
        with self.assertRaises(CommandError) as cm:
            call_command('verify_transactions')
        exception = six.text_type(cm.exception)
        self.assertIn("The following orders are without payments", exception)
        self.assertIn(str(self.order.id), exception)

        try:
            call_command('verify_transactions',
                         '--threshold=1')  # allow 1 anomoly
        except CommandError as e:
            self.fail(
                "Failed to verify transactions when no failure was expected. {}"
                .format(e))

        try:
            call_command(
                'verify_transactions',
                '--threshold=0.25')  # 1-in-4 should be just on the line
        except CommandError as e:
            self.fail(
                "Failed to verify transactions when no failure was expected. {}"
                .format(e))

        with self.assertRaises(CommandError) as cm:
            call_command('verify_transactions', '--threshold=0.2')
        exception = six.text_type(cm.exception)
        self.assertIn("The following orders are without payments", exception)
        self.assertIn(str(self.order.id), exception)
Ejemplo n.º 8
0
 def test_successful_response(self):
     """ Verify a successful response is returned. """
     voucher = VoucherFactory(code='ENROLLMENT')
     order = OrderFactory(user=self.user)
     line = OrderLineFactory(order=order)
     order_line_vouchers = OrderLineVouchers.objects.create(line=line)
     order_line_vouchers.vouchers.add(voucher)
     response = self.client.get(reverse(self.path, args=[order.number]))
     self.assertEqual(response.status_code, 200)
     self.assertEqual(response['content-type'], 'text/csv')
Ejemplo n.º 9
0
    def test_omitting_already_bought_credit_seat(self):
        """ Verify a seat that the user bought is omitted from offer page results. """
        products, request, voucher = self.prepare_get_offers_response(quantity=2, seat_type='credit')
        self.mock_eligibility_api(request, self.user, 'a/b/c', eligible=True)
        offers = VoucherViewSet().get_offers(request=request, voucher=voucher)['results']
        self.assertEqual(len(offers), 2)

        order = OrderFactory(user=self.user)
        order.lines.add(OrderLineFactory(product=products[0]))
        offers = VoucherViewSet().get_offers(request=request, voucher=voucher)['results']
        self.assertEqual(len(offers), 1)
    def setUp(self):
        """
        Create test data.
        """
        super(UpdateEffectiveContractDiscountTests, self).setUp()

        # Set up orders with a enterprise_customer
        self.enterprise_customer_uuid = '123e4567-e89b-12d3-a456-426655440000'
        self.unit_price = 100
        self.condition = ManualEnrollmentOrderDiscountConditionFactory(
            enterprise_customer_uuid=self.enterprise_customer_uuid
        )
        self.offer = ConditionalOfferFactory(condition=self.condition, id=9999)
        self.order = OrderFactory()
        self.order_discount = OrderDiscountFactory(offer_id=self.offer.id, order=self.order)
        self.line = OrderLineFactory(order=self.order, unit_price_excl_tax=self.unit_price)
        self.line.save()
        self.order_discount = OrderDiscountFactory(offer_id=self.offer.id, order=self.order)
        self.order.save()
        self.offer.save()
        self.condition.save()
Ejemplo n.º 11
0
    def test_successful_response(self, product_title):
        """ Verify a successful response is returned. """
        voucher = VoucherFactory()
        order = OrderFactory(user=self.user)
        product = ProductFactory(title=product_title, categories=[])
        line = OrderLineFactory(order=order, product=product)
        order_line_vouchers = OrderLineVouchers.objects.create(line=line)
        order_line_vouchers.vouchers.add(voucher)

        response = self.client.get(reverse(self.path, args=[order.number]))
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response['content-type'], 'text/csv')
Ejemplo n.º 12
0
    def use_voucher(self, voucher, user):
        """
        Mark voucher as used by provided user
        """
        partner = PartnerFactory(short_code='testX')
        course = CourseFactory(id='course-v1:test-org+course+run', partner=partner)
        verified_seat = course.create_or_update_seat('verified', False, 100)

        order = OrderFactory()
        order_line = OrderLineFactory(product=verified_seat, partner_sku='test_sku')
        order.lines.add(order_line)
        voucher.record_usage(order, user)
        voucher.offers.first().record_usage(discount={'freq': 1, 'discount': 1})
Ejemplo n.º 13
0
    def test_convert_course(self, initial_cert_type, direction, new_cert_type):
        """Verify that an honor course can be converted to audit correctly."""
        course = CourseFactory()
        seat_to_convert = course.create_or_update_seat(initial_cert_type, False, 0, self.partner)
        stock_record = StockRecord.objects.get(product=seat_to_convert)
        order_line = OrderLineFactory(stockrecord=stock_record, product=seat_to_convert)

        old_stock_record_sku = stock_record.partner_sku
        old_order_line_sku = order_line.partner_sku

        # Mock the LMS call
        with mock.patch.object(LMSPublisher, 'publish') as mock_publish:
            mock_publish.return_value = True
            call_command(
                'convert_course', course.id, access_token=ACCESS_TOKEN, commit=True,
                direction=direction, partner=self.partner.code
            )

        # Calling refresh_from_db doesn't seem to update the product's attributes
        seat_to_convert = Product.objects.get(pk=seat_to_convert.pk)
        stock_record.refresh_from_db()
        order_line.refresh_from_db()

        self.assertEqual(getattr(seat_to_convert.attr, 'certificate_type', ''), new_cert_type)

        if new_cert_type == '':
            self.assertNotIn('with honor certificate', seat_to_convert.title)
        else:
            self.assertIn(' with honor certificate', seat_to_convert.title)

        # Verify that partner SKUs are correctly updated
        self.assertNotEqual(old_stock_record_sku, stock_record.partner_sku)
        self.assertNotEqual(old_order_line_sku, order_line.partner_sku)
        self.assertEqual(order_line.partner_sku, stock_record.partner_sku)

        self.assertTrue(mock_publish.called)
Ejemplo n.º 14
0
class VerifyTransactionsTest(TestCase):
    def setUp(self):
        # Timestamp in the middle of the time window
        time_delta = (DEFAULT_START_DELTA_TIME + DEFAULT_END_DELTA_TIME) / 2
        self.timestamp = datetime.datetime.now(
            pytz.utc) - datetime.timedelta(minutes=time_delta)

        self.payevent, __ = PaymentEventType.objects.get_or_create(
            name=PaymentEventTypeName.PAID)
        self.refundevent, __ = PaymentEventType.objects.get_or_create(
            name=PaymentEventTypeName.REFUNDED)
        self.seat_product_class, __ = ProductClass.objects.get_or_create(
            name=SEAT_PRODUCT_CLASS_NAME)
        self.order = OrderFactory(total_incl_tax=90,
                                  date_placed=self.timestamp)
        self.product = ProductFactory(product_class=self.seat_product_class,
                                      categories=None)
        self.line = OrderLineFactory(order=self.order,
                                     product=self.product,
                                     partner_sku='test_sku')
        self.line.save()
        self.product.save()
        self.order.save()

    def test_time_window(self):
        """Test verify_transactions only examines the correct time window"""
        with self.assertRaises(CommandError) as cm:
            call_command('verify_transactions')
        exception = six.text_type(cm.exception)
        self.assertIn("The following orders are without payments", exception)
        self.assertIn(str(self.order.id), exception)

        time_outside_window = DEFAULT_START_DELTA_TIME + DEFAULT_END_DELTA_TIME + 1
        time_outside_window_datetime = datetime.datetime.now(
            pytz.utc) - datetime.timedelta(minutes=time_outside_window)
        self.order.date_placed = time_outside_window_datetime
        self.order.save()

        try:
            call_command('verify_transactions')
        except CommandError as e:
            self.fail(
                "Failed to verify transactions when no errors were expected. {}"
                .format(e))

    def test_no_errors(self):
        """Test verify_transactions with order and payment of same amount."""
        payment = PaymentEventFactory(order=self.order,
                                      amount=90,
                                      event_type_id=self.payevent.id,
                                      date_created=self.timestamp)
        payment.save()
        refund = PaymentEventFactory(order=self.order,
                                     amount=90,
                                     event_type_id=self.refundevent.id,
                                     date_created=self.timestamp)
        refund.save()
        try:
            call_command('verify_transactions')
        except CommandError as e:
            self.fail(
                "Failed to verify transactions when no errors were expected. {}"
                .format(e))

    def test_zero_dollar_order(self):
        """Verify zero dollar orders are not flagged as errors."""
        total_incl_tax_before = self.order.total_incl_tax
        self.order.total_incl_tax = 0
        self.order.save()
        try:
            call_command('verify_transactions')
        except CommandError as e:
            self.fail(
                "Failed to verify transactions when no errors were expected. {}"
                .format(e))
        finally:
            self.order.total_incl_tax = total_incl_tax_before
            self.order.save()

    def test_no_payment_for_valid_product_order(self):
        """Verify errors are thrown when there are valid product orders without payments."""
        with self.assertRaises(CommandError) as cm:
            call_command('verify_transactions')
        exception = six.text_type(cm.exception)
        self.assertIn("The following orders are without payments", exception)
        self.assertIn(str(self.order.id), exception)

    def test_no_payment_for_filtered_product_order(self):
        """Verify errors are not thrown when there are filtered product orders without payments."""
        new_product_class, __ = ProductClass.objects.get_or_create(
            name="Test Product Class")
        self.product.product_class = new_product_class
        self.product.save()

        try:
            call_command('verify_transactions')
        except CommandError as e:
            self.fail(
                "Failed to verify transactions when no errors were expected. {}"
                .format(e))
        finally:
            self.product.product_class = self.seat_product_class
            self.product.save()

    def test_two_same_payments_for_order(self):
        """ Verify that errors are thrown when their are multiple payments on an order."""
        payment1 = PaymentEventFactory(order=self.order,
                                       amount=90,
                                       event_type_id=self.payevent.id,
                                       date_created=self.timestamp)
        payment2 = PaymentEventFactory(order=self.order,
                                       amount=90,
                                       event_type_id=self.payevent.id,
                                       date_created=self.timestamp)
        payment1.save()
        payment2.save()
        with self.assertRaises(CommandError) as cm:
            call_command('verify_transactions')
        exception = six.text_type(cm.exception)
        self.assertIn("The following orders had multiple payments ", exception)
        self.assertIn(str(self.order.id), exception)
        self.assertIn(str(payment1.id), exception)
        self.assertIn(str(payment2.id), exception)

    def test_multiple_payments_for_order(self):
        """ Verify that errors are thrown when their are multiple payments on an order."""
        payment1 = PaymentEventFactory(order=self.order,
                                       amount=90,
                                       event_type_id=self.payevent.id,
                                       date_created=self.timestamp)
        payment2 = PaymentEventFactory(order=self.order,
                                       amount=90,
                                       event_type_id=self.payevent.id,
                                       date_created=self.timestamp)
        payment3 = PaymentEventFactory(order=self.order,
                                       amount=90,
                                       event_type_id=self.payevent.id,
                                       date_created=self.timestamp)
        payment1.save()
        payment2.save()
        payment3.save()
        with self.assertRaises(CommandError) as cm:
            call_command('verify_transactions')
        exception = six.text_type(cm.exception)
        self.assertIn("The following orders had multiple payments ", exception)
        self.assertIn(str(self.order.id), exception)
        self.assertIn(str(payment1.id), exception)
        self.assertIn(str(payment2.id), exception)
        self.assertIn(str(payment3.id), exception)

    def test_totals_mismatch(self):
        """ Verify errors thrown when payment and order totals don't match."""
        payment = PaymentEventFactory(order=self.order,
                                      amount=100,
                                      event_type_id=self.payevent.id,
                                      date_created=self.timestamp)
        payment.save()
        with self.assertRaises(CommandError) as cm:
            call_command('verify_transactions')
        exception = six.text_type(cm.exception)
        self.assertIn("Order totals mismatch with payments received",
                      exception)
        self.assertIn(str(self.order.id), exception)
        self.assertIn(str(payment.id), exception)
        self.assertIn("Amount: 90.00", exception)
        self.assertIn("Amount: 100.00", exception)
        self.assertIn("Amount: 100.00", exception)

    def test_refund_exceeded(self):
        """Test verify_transactions with refund which exceed amount paid."""
        payment = PaymentEventFactory(order=self.order,
                                      amount=90,
                                      event_type_id=self.payevent.id,
                                      date_created=self.timestamp)
        payment.save()
        refund = PaymentEventFactory(order=self.order,
                                     amount=100,
                                     event_type_id=self.refundevent.id,
                                     date_created=self.timestamp)
        refund.save()
        with self.assertRaises(CommandError) as cm:
            call_command('verify_transactions')
        exception = six.text_type(cm.exception)
        self.assertIn("The following orders had excessive refunds", exception)
        self.assertIn(str(self.order.id), exception)
        self.assertIn(str(refund.id), exception)
        self.assertIn("Amount: 90.00", exception)
        self.assertIn("Amount: 100.00", exception)
Ejemplo n.º 15
0
class VerifyTransactionsTest(TestCase):

    def setUp(self):
        # Timestamp in the middle of the time window
        time_delta = (DEFAULT_START_DELTA_TIME + DEFAULT_END_DELTA_TIME) / 2
        self.timestamp = datetime.datetime.now(pytz.utc) - datetime.timedelta(minutes=time_delta)

        self.payevent, __ = PaymentEventType.objects.get_or_create(name=PaymentEventTypeName.PAID)
        self.refundevent, __ = PaymentEventType.objects.get_or_create(name=PaymentEventTypeName.REFUNDED)
        self.seat_product_class, __ = ProductClass.objects.get_or_create(name=SEAT_PRODUCT_CLASS_NAME)
        self.order = OrderFactory(total_incl_tax=90, date_placed=self.timestamp)
        self.product = ProductFactory(product_class=self.seat_product_class, categories=None)
        self.line = OrderLineFactory(order=self.order, product=self.product, partner_sku='test_sku')
        self.line.save()
        self.product.save()
        self.order.save()

    def test_time_window(self):
        """ Test verify_transactions only examines the correct time window """
        with self.assertRaises(CommandError) as cm:
            call_command('verify_transactions')
        exception = six.text_type(cm.exception)
        self.assertIn("The following orders are without payments", exception)
        self.assertIn(str(self.order.id), exception)

        time_outside_window = DEFAULT_START_DELTA_TIME + DEFAULT_END_DELTA_TIME + 1
        time_outside_window_datetime = datetime.datetime.now(pytz.utc) - datetime.timedelta(minutes=time_outside_window)
        self.order.date_placed = time_outside_window_datetime
        self.order.save()

        try:
            call_command('verify_transactions')
        except CommandError as e:
            self.fail("Failed to verify transactions when no errors were expected. {}".format(e))

    def test_threshold(self):
        """ Test verify_transactions only fails if there are too many anomolies """
        for i in range(3):
            # Create some "good" orders w/ payments
            order = OrderFactory(total_incl_tax=50 + i, date_placed=self.timestamp)
            line = OrderLineFactory(order=order, product=self.product, partner_sku='test_sku')
            payment = PaymentEventFactory(
                order=order,
                amount=50 + i,
                event_type_id=self.payevent.id,
                date_created=self.timestamp
            )
            payment.save()
            line.save()
            order.save()

        # self.order fixture should still have no payment
        with self.assertRaises(CommandError) as cm:
            call_command('verify_transactions')
        exception = six.text_type(cm.exception)
        self.assertIn("The following orders are without payments", exception)
        self.assertIn(str(self.order.id), exception)

        try:
            call_command('verify_transactions', '--threshold=1')  # allow 1 anomoly
        except CommandError as e:
            self.fail("Failed to verify transactions when no failure was expected. {}".format(e))

        try:
            call_command('verify_transactions', '--threshold=0.25')  # 1-in-4 should be just on the line
        except CommandError as e:
            self.fail("Failed to verify transactions when no failure was expected. {}".format(e))

        with self.assertRaises(CommandError) as cm:
            call_command('verify_transactions', '--threshold=0.2')
        exception = six.text_type(cm.exception)
        self.assertIn("The following orders are without payments", exception)
        self.assertIn(str(self.order.id), exception)

    def test_no_errors(self):
        """ Test verify_transactions with order and payment of same amount """
        payment = PaymentEventFactory(order=self.order,
                                      amount=90,
                                      event_type_id=self.payevent.id,
                                      date_created=self.timestamp)
        payment.save()
        refund = PaymentEventFactory(order=self.order,
                                     amount=90,
                                     event_type_id=self.refundevent.id,
                                     date_created=self.timestamp)
        refund.save()
        try:
            call_command('verify_transactions')
        except CommandError as e:
            self.fail("Failed to verify transactions when no errors were expected. {}".format(e))

    def test_zero_dollar_order(self):
        """ Verify zero dollar orders are not flagged as errors """
        total_incl_tax_before = self.order.total_incl_tax
        self.order.total_incl_tax = 0
        self.order.save()
        try:
            call_command('verify_transactions')
        except CommandError as e:
            self.fail("Failed to verify transactions when no errors were expected. {}".format(e))
        finally:
            self.order.total_incl_tax = total_incl_tax_before
            self.order.save()

    def test_no_payment_for_valid_product_order(self):
        """ Verify errors are thrown when there are valid product orders without payments """
        with self.assertRaises(CommandError) as cm:
            call_command('verify_transactions')
        exception = six.text_type(cm.exception)
        self.assertIn("The following orders are without payments", exception)
        self.assertIn(str(self.order.id), exception)

    def test_no_payment_for_filtered_product_order(self):
        """ Verify errors are not thrown when there are filtered product orders without payments """
        new_product_class, __ = ProductClass.objects.get_or_create(name="Test Product Class")
        self.product.product_class = new_product_class
        self.product.save()

        try:
            call_command('verify_transactions')
        except CommandError as e:
            self.fail("Failed to verify transactions when no errors were expected. {}".format(e))
        finally:
            self.product.product_class = self.seat_product_class
            self.product.save()

    def test_two_same_payments_for_order(self):
        """ Verify that errors are thrown when their are multiple payments on an order """
        payment1 = PaymentEventFactory(order=self.order,
                                       amount=90,
                                       event_type_id=self.payevent.id,
                                       date_created=self.timestamp)
        payment2 = PaymentEventFactory(order=self.order,
                                       amount=90,
                                       event_type_id=self.payevent.id,
                                       date_created=self.timestamp)
        payment1.save()
        payment2.save()
        with self.assertRaises(CommandError) as cm:
            call_command('verify_transactions')
        exception = six.text_type(cm.exception)
        self.assertIn("The following orders had multiple payments", exception)
        self.assertIn(str(self.order.id), exception)
        self.assertIn(str(payment1.id), exception)
        self.assertIn(str(payment2.id), exception)

    def test_multiple_payments_for_order(self):
        """ Verify that errors are thrown when their are multiple payments on an order """
        payment1 = PaymentEventFactory(order=self.order,
                                       amount=90,
                                       event_type_id=self.payevent.id,
                                       date_created=self.timestamp)
        payment2 = PaymentEventFactory(order=self.order,
                                       amount=90,
                                       event_type_id=self.payevent.id,
                                       date_created=self.timestamp)
        payment3 = PaymentEventFactory(order=self.order,
                                       amount=90,
                                       event_type_id=self.payevent.id,
                                       date_created=self.timestamp)
        payment1.save()
        payment2.save()
        payment3.save()
        with self.assertRaises(CommandError) as cm:
            call_command('verify_transactions')
        exception = six.text_type(cm.exception)
        self.assertIn("The following orders had multiple payments", exception)
        self.assertIn(str(self.order.id), exception)
        self.assertIn(str(payment1.id), exception)
        self.assertIn(str(payment2.id), exception)
        self.assertIn(str(payment3.id), exception)

    @ddt.data(80, 100)
    def test_totals_mismatch(self, amount):
        """ Verify errors thrown when payment and order totals don't match """
        payment = PaymentEventFactory(order=self.order,
                                      amount=amount,
                                      event_type_id=self.payevent.id,
                                      date_created=self.timestamp)
        payment.save()
        with self.assertRaises(CommandError) as cm:
            call_command('verify_transactions')
        exception = six.text_type(cm.exception)
        self.assertIn("The following order totals mismatch payments received", exception)
        self.assertIn(str(self.order.id), exception)
        self.assertIn(str(payment.id), exception)
        self.assertIn('"amount": 90.0', exception)
        self.assertIn('"amount": {}'.format(amount), exception)

    def test_totals_mismatch_support(self):
        """ Verify errors thrown when payment amount is greater
        than order amount and a refund is required from Support """
        payment = PaymentEventFactory(order=self.order,
                                      amount=100,
                                      event_type_id=self.payevent.id,
                                      date_created=self.timestamp)
        payment.save()
        with self.assertRaises(CommandError) as cm:
            call_command('verify_transactions', '--support')
        exception = six.text_type(cm.exception)
        self.assertTrue(payment.amount != self.order.total_incl_tax)
        self.assertIn("There was a mismatch in the totals in the following order that require a refund", exception)
        self.assertIn("orders_mismatched_totals_support", exception)
        self.assertIn(str(self.order.id), exception)
        self.assertIn(str(payment.id), exception)
        self.assertIn('"order_amount": 90.0', exception)
        self.assertIn('"payment_amount": 100.0', exception)
        self.assertIn('"refund_amount": 10.0', exception)

    def test_refund_exceeded(self):
        """ Test verify_transactions with refund which exceed amount paid """
        payment = PaymentEventFactory(order=self.order,
                                      amount=90,
                                      event_type_id=self.payevent.id,
                                      date_created=self.timestamp)
        payment.save()
        refund = PaymentEventFactory(order=self.order,
                                     amount=100,
                                     event_type_id=self.refundevent.id,
                                     date_created=self.timestamp)
        refund.save()
        with self.assertRaises(CommandError) as cm:
            call_command('verify_transactions')
        exception = six.text_type(cm.exception)
        self.assertIn("The following orders had excessive refunds", exception)
        self.assertIn(str(self.order.id), exception)
        self.assertIn(str(refund.id), exception)
        self.assertIn('"amount": 90.0', exception)
        self.assertIn('"amount": 100.0', exception)