Beispiel #1
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)
Beispiel #2
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)