예제 #1
0
    def handle(self, *args, **options):
        proforma = ProformaFactory.create(
            proforma_entries=[DocumentEntryFactory.create()],
            state=Proforma.STATES.ISSUED)
        proforma.create_invoice()

        invoice = InvoiceFactory.create(
            invoice_entries=[DocumentEntryFactory.create()],
            state=Invoice.STATES.ISSUED,
            related_document=None)
        TransactionFactory.create(state=Transaction.States.Settled,
                                  invoice=invoice,
                                  payment_method__customer=invoice.customer,
                                  proforma=None)
        InvoiceFactory.create_batch(
            size=3,
            invoice_entries=[DocumentEntryFactory.create()],
            state=Invoice.STATES.PAID,
            related_document=None)
        InvoiceFactory.create_batch(
            size=3,
            invoice_entries=[DocumentEntryFactory.create()],
            state=Invoice.STATES.DRAFT,
            related_document=None)

        InvoiceFactory.create_batch(
            size=3,
            invoice_entries=[DocumentEntryFactory.create()],
            state=Invoice.STATES.CANCELED,
            related_document=None)
    def test_cancel_action(self):
        payment_method = self.create_payment_method(
            customer=self.customer, payment_processor='triggered')
        transaction_initial = TransactionFactory.create(
            payment_method=payment_method)
        transaction_pending = TransactionFactory.create(
            payment_method=payment_method, state='pending')

        url = reverse('payment-method-action',
                      kwargs={
                          'customer_pk': self.customer.pk,
                          'payment_method_id': payment_method.pk,
                          'requested_action': 'cancel',
                      })

        response = self.client.post(url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        payment_method.refresh_from_db()
        transaction_initial.refresh_from_db()
        transaction_pending.refresh_from_db()

        self.assertTrue(payment_method.canceled)
        self.assertEqual(transaction_initial.state,
                         Transaction.States.Canceled)
        self.assertEqual(transaction_pending.state,
                         Transaction.States.Canceled)
예제 #3
0
    def test_skip_transaction_with_unverified_payment_method(self):
        payment_method = PaymentMethodFactory.create(
            payment_processor=triggered_processor, verified=False)

        TransactionFactory.create(payment_method=payment_method)

        mock_execute = MagicMock()
        with patch.multiple(TriggeredProcessor,
                            execute_transaction=mock_execute):
            call_command('execute_transactions')

            self.assertEqual(mock_execute.call_count, 0)
예제 #4
0
    def test_filter_payment_method(self):
        customer = CustomerFactory.create()
        payment_method = PaymentMethodFactory.create(
            payment_processor=triggered_processor,
            customer=customer
        )

        transaction1 = TransactionFactory.create(
            payment_method=payment_method
        )
        transaction_data_1 = self._transaction_data(transaction1)

        transaction2 = TransactionFactory.create(
            payment_method=payment_method
        )
        transaction_data_2 = self._transaction_data(transaction2)

        urls = [
            reverse(
                'payment-method-transaction-list', kwargs={
                    'customer_pk': customer.pk,
                    'payment_method_id': payment_method.pk}),
            reverse(
                'transaction-list', kwargs={'customer_pk': customer.pk})]

        for url in urls:
            url_method_someprocessor = (
                url + '?payment_processor=' + triggered_processor
            )

            url_no_output = url + '?payment_processor=Random'

            with patch('silver.utils.payments._get_jwt_token') as mocked_token:
                mocked_token.return_value = 'token'

                response = self.client.get(url_method_someprocessor, format='json')
                self.assertEqual(response.status_code, status.HTTP_200_OK)

                transaction1.refresh_from_db()
                transaction_data_1['updated_at'] = response.data[1]['updated_at']

                transaction1.refresh_from_db()
                transaction_data_2['updated_at'] = response.data[0]['updated_at']

                self.assertEqual(response.data[1], transaction_data_1)
                self.assertEqual(response.data[0], transaction_data_2)

                response = self.client.get(url_no_output, format='json')
                self.assertEqual(response.status_code, status.HTTP_200_OK)
                self.assertEqual(response.data, [])
예제 #5
0
    def test_transaction_filtering(self):
        payment_method = PaymentMethodFactory.create(
            payment_processor=triggered_processor, verified=True)

        transactions = TransactionFactory.create_batch(
            5, payment_method=payment_method)

        filtered_transactions = [
            transactions[0], transactions[2], transactions[4]
        ]

        mock_execute = MagicMock()
        with patch.multiple(TriggeredProcessor,
                            execute_transaction=mock_execute):
            transactions_arg = [
                str(transaction.pk) for transaction in filtered_transactions
            ]
            call_command('execute_transactions',
                         '--transactions=%s' % ','.join(transactions_arg))

            for transaction in filtered_transactions:
                self.assertIn(call(transaction), mock_execute.call_args_list)

            self.assertEqual(mock_execute.call_count,
                             len(filtered_transactions))
예제 #6
0
def test_get_invoice(authenticated_api_client, settings, issued_invoice):
    invoice = issued_invoice
    customer = issued_invoice.customer

    issued_invoice.generate_pdf()

    with mute_signals(pre_save):
        [
            TransactionFactory.create(
                state=state,
                invoice=issued_invoice,
                payment_method=PaymentMethodFactory(customer=customer))
            for state in Transaction.States.as_list() if state not in [
                Transaction.States.Canceled, Transaction.States.Refunded,
                Transaction.States.Failed
            ]
        ]

    url = reverse('invoice-detail', kwargs={'pk': invoice.pk})

    response = authenticated_api_client.get(url, format='json')

    assert response.status_code == status.HTTP_200_OK, response.data

    # Cast IDs to UUID so the comparison check doesn't fail
    data = response.data
    data['transactions'][0]['id'] = UUID(data['transactions'][0]['id'])
    data['transactions'][1]['id'] = UUID(data['transactions'][1]['id'])
    data['transactions'][2]['id'] = UUID(data['transactions'][2]['id'])

    invoice_definition.check_response(invoice, response_data=response.data)
    def test_fetch_transaction_status_transactions_filtering(self):
        payment_method = PaymentMethodFactory.create(
            payment_processor=triggered_processor)

        transactions = TransactionFactory.create_batch(
            5, payment_method=payment_method, state=Transaction.States.Pending)

        filtered_transactions = [
            transactions[0], transactions[2], transactions[4]
        ]

        mock_fetch_status = MagicMock()
        with patch.multiple(TriggeredProcessor,
                            fetch_transaction_status=mock_fetch_status):
            transactions_arg = [
                str(transaction.pk) for transaction in filtered_transactions
            ]
            call_command('fetch_transactions_status',
                         '--transactions=%s' % ','.join(transactions_arg))

            for transaction in filtered_transactions:
                self.assertIn(call(transaction),
                              mock_fetch_status.call_args_list)

            self.assertEqual(mock_fetch_status.call_count,
                             len(filtered_transactions))
예제 #8
0
    def test_documents_list_case_1(self):
        """
            One proforma, one invoice, without related documents
        """
        proforma = ProformaFactory.create()
        invoice_entries = DocumentEntryFactory.create_batch(3)
        invoice = InvoiceFactory.create(invoice_entries=invoice_entries)
        invoice.issue()
        payment_method = PaymentMethodFactory.create(customer=invoice.customer)
        transaction = TransactionFactory.create(payment_method=payment_method,
                                                invoice=invoice)

        url = reverse('document-list')

        with patch('silver.utils.payments._get_jwt_token',
                   new=self._jwt_token):
            response = self.client.get(url)

        # ^ there's a bug where specifying format='json' doesn't work
        response_data = response.data

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response_data), 2)

        self.assertIn(self._get_expected_data(invoice, [transaction]),
                      response_data)

        self.assertIn(self._get_expected_data(proforma), response_data)
예제 #9
0
    def test_filter_min_max_amount(self):
        payment_method = PaymentMethodFactory.create(
            payment_processor=triggered_processor, )
        customer = payment_method.customer

        entry = DocumentEntryFactory(quantity=1, unit_price=100)
        invoice = InvoiceFactory.create(invoice_entries=[entry],
                                        customer=customer)
        invoice.issue()

        transaction = TransactionFactory.create(payment_method=payment_method,
                                                invoice=invoice)

        transaction_data = self._transaction_data(transaction)

        urls = [
            reverse('payment-method-transaction-list',
                    kwargs={
                        'customer_pk': customer.pk,
                        'payment_method_id': payment_method.pk
                    }),
            reverse('transaction-list', kwargs={'customer_pk': customer.pk})
        ]

        for url in urls:
            url_with_filterable_data = url + '?min_amount=10'
            url_no_output = url + '?min_amount=150'

            with patch('silver.utils.payments._get_jwt_token') as mocked_token:
                mocked_token.return_value = 'token'

                response = self.client.get(url_with_filterable_data,
                                           format='json')

                transaction.refresh_from_db()
                transaction_data['updated_at'] = response.data[0]['updated_at']

                self.assertEqual(response.status_code, status.HTTP_200_OK)
                self.assertEqual(response.data[0], transaction_data)

                response = self.client.get(url_no_output, format='json')
                self.assertEqual(response.status_code, status.HTTP_200_OK)
                self.assertEqual(response.data, [])

                url_with_filterable_data = url + '?max_amount=1050'
                url_no_output = url + '?max_amount=10'

                response = self.client.get(url_with_filterable_data,
                                           format='json')

                transaction.refresh_from_db()
                transaction_data['updated_at'] = response.data[0]['updated_at']

                self.assertEqual(response.status_code, status.HTTP_200_OK)
                self.assertEqual(response.data[0], transaction_data)

                response = self.client.get(url_no_output, format='json')
                self.assertEqual(response.status_code, status.HTTP_200_OK)
                self.assertEqual(response.data, [])
예제 #10
0
    def test_cancel_action(self):
        transaction_initial = TransactionFactory.create(state='initial')
        transaction_pending = TransactionFactory.create(state='pending')

        for transaction in [transaction_initial, transaction_pending]:
            url = reverse('transaction-action', kwargs={
                'customer_pk': transaction.payment_method.customer.pk,
                'transaction_uuid': str(transaction.uuid),
                'requested_action': 'cancel',
            })

            response = self.client.post(url)
            self.assertEqual(response.status_code, status.HTTP_200_OK)

            transaction.refresh_from_db()
            self.assertEqual(transaction.state,
                             Transaction.States.Canceled)
예제 #11
0
    def test_exception_logging(self, mock_logger):
        payment_method = PaymentMethodFactory.create(
            payment_processor=triggered_processor, verified=True)

        TransactionFactory.create(payment_method=payment_method)

        mock_execute = MagicMock()
        mock_execute.side_effect = Exception('This happened.')

        with patch.multiple(TriggeredProcessor,
                            execute_transaction=mock_execute):
            call_command('execute_transactions')
            expected_call = call(
                'Encountered exception while executing transaction with id=%s.',
                1,
                exc_info=True)

            self.assertEqual(expected_call, mock_logger.call_args)
예제 #12
0
    def test_get_transaction_from_token(self):
        transaction = TransactionFactory()

        mocked_view = MagicMock()
        token = _get_jwt_token(transaction)

        self.assertEqual(get_transaction_from_token(mocked_view)(None, token),
                         mocked_view())
        mocked_view.has_calls([call(None, transaction, False), call()])
예제 #13
0
    def test_transaction_update_status_exception_logging(self, mock_logger):
        payment_method = PaymentMethodFactory.create(
            payment_processor=triggered_processor)

        TransactionFactory.create(payment_method=payment_method,
                                  state=Transaction.States.Pending)

        mock_fetch_status = MagicMock()
        mock_fetch_status.side_effect = Exception('This happened.')

        with patch.multiple(TriggeredProcessor,
                            fetch_transaction_status=mock_fetch_status):
            call_command('fetch_transactions_status')
            expected_call = call(
                'Encountered exception while updating transaction with id=%s.',
                1,
                exc_info=True)

            self.assertEqual(expected_call, mock_logger.call_args)
예제 #14
0
    def test_get_payment_url(self):
        transaction = TransactionFactory()

        expected_url = '/pay/token/'
        with patch('silver.utils.payments._get_jwt_token') as mocked_token:
            mocked_token.return_value = 'token'

            self.assertEqual(get_payment_url(transaction, None), expected_url)

            assert mocked_token.mock_calls == [call(transaction)]
예제 #15
0
    def test_list_transactions(self):
        customer = CustomerFactory.create()
        payment_method = PaymentMethodFactory.create(customer=customer)

        transaction_1 = TransactionFactory.create(payment_method=payment_method)
        expected_t1 = self._transaction_data(transaction_1)
        transaction_2 = TransactionFactory.create(payment_method=payment_method)
        expected_t2 = self._transaction_data(transaction_2)

        with patch('silver.utils.payments._get_jwt_token') as mocked_token:
            mocked_token.return_value = 'token'

            url = reverse('transaction-list',
                          kwargs={'customer_pk': customer.pk})

            response = self.client.get(url, format='json')

            self.assertEqual(response.data[1], expected_t1)
            self.assertEqual(response.data[0], expected_t2)
예제 #16
0
    def test_pay_documents_on_transaction_settle(self):
        transaction = TransactionFactory.create(
            state=Transaction.States.Pending
        )
        transaction.settle()

        proforma = transaction.proforma
        invoice = transaction.invoice

        self.assertEqual(proforma.state, proforma.STATES.PAID)
        self.assertEqual(invoice.state, invoice.STATES.PAID)
예제 #17
0
    def test_get_transaction_from_expired_token(self):
        transaction = TransactionFactory()

        mocked_view = MagicMock()
        with patch('silver.utils.payments.datetime') as mocked_datetime:
            mocked_datetime.utcnow.return_value = datetime.utcnow() - timedelta(days=2 * 365)
            token = _get_jwt_token(transaction)

        self.assertEqual(get_transaction_from_token(mocked_view)(None, token),
                         mocked_view())
        mocked_view.has_calls([call(None, transaction, True), call()])
예제 #18
0
    def test_cancel_action_failed_void(self):
        payment_method = self.create_payment_method(
            customer=self.customer, payment_processor=failing_void_processor
        )

        transaction_initial = TransactionFactory.create(payment_method=payment_method)
        transaction_pending = TransactionFactory.create(payment_method=payment_method,
                                                        state='pending')

        url = reverse('payment-method-action', kwargs={
            'customer_pk': self.customer.pk,
            'payment_method_id': payment_method.pk,
            'requested_action': 'cancel',
        })

        response = self.client.post(url)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

        expected_error = "Transaction {} couldn't be voided".format(transaction_pending.uuid)
        self.assertEqual(response.data, {'errors': [expected_error]})
예제 #19
0
    def test_pay_transaction_view_not_consumable_transaction(self):
        last_year = timezone.now() - timedelta(days=365)
        transaction = TransactionFactory.create(
            state=Transaction.States.Initial, valid_until=last_year)

        response = self.client.get(get_payment_url(transaction, None))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(
            force_str(response.content),
            render_to_string('transactions/expired_payment.html', {
                'document': transaction.document,
            }))
예제 #20
0
    def test_pay_transaction_view_invalid_state(self):
        transaction = TransactionFactory.create(
            state=Transaction.States.Settled)

        response = self.client.get(get_payment_url(transaction, None))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(
            force_str(response.content),
            render_to_string('transactions/complete_payment.html', {
                'transaction': transaction,
                'document': transaction.document,
            }))
예제 #21
0
    def test_transaction_settle_with_already_paid_invoice(self):
        transaction = TransactionFactory.create(
            state=Transaction.States.Pending,
        )

        transaction.invoice.pay()

        transaction.settle()

        transaction.invoice.refresh_from_db()
        transaction.refresh_from_db()

        assert transaction.state == Transaction.States.Settled
        assert transaction.invoice.state == Invoice.STATES.PAID
예제 #22
0
    def test_complete_payment_view_with_return_url(self):
        transaction = TransactionFactory.create(
            state=Transaction.States.Settled)

        return_url = 'http://home.com'
        complete_url = "{}?return_url={}".format(
            get_payment_complete_url(transaction, None), return_url)
        expected_url = "{}?transaction_uuid={}".format(return_url,
                                                       transaction.uuid)

        response = self.client.get(complete_url, follow=False)
        self.assertRedirects(response,
                             expected_url,
                             fetch_redirect_response=False)
예제 #23
0
    def test_patch_transaction_not_allowed_fields(self):
        payment_method = PaymentMethodFactory.create(
            payment_processor=triggered_processor)
        customer = payment_method.customer
        transaction = TransactionFactory.create(payment_method=payment_method)

        proforma = ProformaFactory.create(state='issued', customer=customer)
        invoice = InvoiceFactory.create(state='issued',
                                        customer=customer,
                                        related_document=proforma)
        proforma.related_document = invoice
        proforma.save()

        invoice_url = reverse('invoice-detail', args=[invoice.pk])
        proforma_url = reverse('proforma-detail', args=[proforma.pk])
        url = reverse('transaction-detail',
                      args=[transaction.customer.pk, transaction.uuid])

        new_payment_method = PaymentMethodFactory.create(
            payment_processor=triggered_processor, customer=customer)

        new_payment_method_url = reverse('payment-method-detail',
                                         kwargs={
                                             'customer_pk':
                                             new_payment_method.customer.pk,
                                             'payment_method_id':
                                             new_payment_method.pk
                                         })

        data = {
            'proforma': proforma_url,
            'invoice': invoice_url,
            'currency': 'EUR',
            'amount': 1234,
            'payment_method': new_payment_method_url
        }

        response = self.client.patch(url, format='json', data=data)

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

        self.assertEqual(
            response.data, {
                'proforma': [u'This field may not be modified.'],
                'invoice': [u'This field may not be modified.'],
                'currency': [u'This field may not be modified.'],
                'amount': [u'This field may not be modified.'],
                'payment_method': [u'This field may not be modified.']
            })
예제 #24
0
    def test_complete_payment_view_without_return_url(self):
        transaction = TransactionFactory.create(
            state=Transaction.States.Settled)

        response = self.client.get(get_payment_complete_url(transaction, None))

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(
            force_text(response.content),
            render_to_string(
                'transactions/complete_payment.html', {
                    'expired': False,
                    'transaction': transaction,
                    'document': transaction.document,
                }))
예제 #25
0
    def test_get_payment_complete_url(self):
        transaction = TransactionFactory()

        expected_url = '/pay/token/complete?return_url=http://google.com'
        mocked_request = MagicMock(GET={'return_url': 'http://google.com'},
                                   versioning_scheme=None)
        mocked_request.build_absolute_uri.return_value = '/pay/token/complete'

        with patch('silver.utils.payments._get_jwt_token') as mocked_token:
            mocked_token.return_value = 'token'

            self.assertEqual(get_payment_complete_url(transaction, mocked_request),
                             expected_url)

            assert mocked_token.mock_calls == [call(transaction)]
예제 #26
0
    def test_invalid_transaction_action(self):
        transaction = TransactionFactory.create(state='settled')

        url = reverse('transaction-action', kwargs={
            'customer_pk': transaction.payment_method.customer.pk,
            'transaction_uuid': str(transaction.uuid),
            'requested_action': 'cancel',
        })

        response = self.client.post(url)
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

        expected_error = "Can't execute action because the transaction is in "\
                         "an incorrect state: settled"
        self.assertEqual(response.data, {'errors': expected_error})
예제 #27
0
    def test_pay_transaction_view_expired(self):
        transaction = TransactionFactory.create()

        with patch('silver.utils.payments.datetime') as mocked_datetime:
            mocked_datetime.utcnow.return_value = datetime.utcnow(
            ) - timedelta(days=365)
            url = get_payment_url(transaction, None)

        response = self.client.get(url)

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(
            force_str(response.content),
            render_to_string('transactions/expired_payment.html', {
                'document': transaction.document,
            }))
예제 #28
0
    def test_get_transaction(self):
        customer = CustomerFactory.create()
        payment_method = PaymentMethodFactory.create(customer=customer)

        transaction = TransactionFactory.create(payment_method=payment_method)
        expected = self._transaction_data(transaction)

        with patch('silver.utils.payments._get_jwt_token') as mocked_token:
            mocked_token.return_value = 'token'

            url = reverse('transaction-detail',
                          kwargs={'customer_pk': customer.pk,
                                  'transaction_uuid': transaction.uuid})
            response = self.client.get(url, format='json')

            self.assertEqual(response.data, dict(expected))
예제 #29
0
    def test_transaction_executing(self):
        payment_method = PaymentMethodFactory.create(
            payment_processor=triggered_processor, verified=True)

        transactions = TransactionFactory.create_batch(
            5, payment_method=payment_method)

        mock_execute = MagicMock()
        with patch.multiple(TriggeredProcessor,
                            execute_transaction=mock_execute):
            call_command('execute_transactions')

            for transaction in transactions:
                self.assertIn(call(transaction), mock_execute.call_args_list)

            self.assertEqual(mock_execute.call_count, len(transactions))
    def test_fetch_transaction_status_call(self):
        payment_method = PaymentMethodFactory.create(
            payment_processor=triggered_processor)

        transactions = TransactionFactory.create_batch(
            5, payment_method=payment_method, state=Transaction.States.Pending)

        mock_fetch_status = MagicMock()
        with patch.multiple(TriggeredProcessor,
                            fetch_transaction_status=mock_fetch_status):
            call_command('fetch_transactions_status')

            for transaction in transactions:
                self.assertIn(call(transaction),
                              mock_fetch_status.call_args_list)

            self.assertEqual(mock_fetch_status.call_count, len(transactions))