Beispiel #1
0
    def test_ongoing(self):
        """
        Test that given:
            session 1 - order 1 - status created
            session 2 - order 1 - status submitted
            session 3 - order 1 - status failed
            session 4 - order 2 - status started
            session 5 - order 2 - status success
            session 6 - order 2 - status cancelled

        the method .ongoing() on the queryset only returns the sessions
        which are considered not finished.
        """
        order1, order2 = OrderWithAcceptedQuoteFactory.create_batch(2)

        order1_sessions = PaymentGatewaySessionFactory.create_batch(
            3,
            order=order1,
            status=factory.Iterator([
                PaymentGatewaySessionStatus.CREATED,
                PaymentGatewaySessionStatus.SUBMITTED,
                PaymentGatewaySessionStatus.FAILED,
            ]),
        )
        order2_sessions = PaymentGatewaySessionFactory.create_batch(
            3,
            order=order2,
            status=factory.Iterator([
                PaymentGatewaySessionStatus.STARTED,
                PaymentGatewaySessionStatus.SUCCESS,
                PaymentGatewaySessionStatus.CANCELLED,
            ]),
        )

        # test qs without filters
        qs = PaymentGatewaySession.objects.ongoing()
        assert set(qs.values_list('id', flat=True)) == {
            order1_sessions[0].id,
            order1_sessions[1].id,
            order2_sessions[0].id,
        }

        # test qs with order filter
        qs = PaymentGatewaySession.objects.filter(order=order1).ongoing()
        assert set(qs.values_list('id', flat=True)) == {
            order1_sessions[0].id,
            order1_sessions[1].id,
        }
 def test_404_if_session_belongs_to_another_order(self, public_omis_api_client):
     """
     Test that if the payment gateway session belongs to another order,
     the endpoint returns 404.
     """
     orders = OrderWithAcceptedQuoteFactory.create_batch(2)
     sessions = PaymentGatewaySessionFactory.create_batch(2, order=factory.Iterator(orders))
     url = reverse(
         'api-v3:public-omis:payment-gateway-session:detail',
         kwargs={
             'public_token': orders[0].public_token,
             'pk': sessions[1].id,
         },
     )
     response = public_omis_api_client.get(url)
     assert response.status_code == status.HTTP_404_NOT_FOUND
Beispiel #3
0
    def test_one_failed_refresh_doesnt_stop_others(self, requests_mock):
        """
        Test that if one refresh fails, the other ones are still carried on
        and committed to the databasea.

        In this example, pay-1 and pay-3 should get refreshed whilst pay-2
        errors and shouldn't get refreshed.
        """
        # mock calls to GOV.UK Pay
        govuk_payment_ids = ['pay-1', 'pay-2', 'pay-3']
        requests_mock.get(
            govuk_url(f'payments/{govuk_payment_ids[0]}'),
            status_code=200,
            json={'state': {
                'status': 'failed'
            }},
        )
        requests_mock.get(
            govuk_url(f'payments/{govuk_payment_ids[1]}'),
            status_code=500,
        )
        requests_mock.get(
            govuk_url(f'payments/{govuk_payment_ids[2]}'),
            status_code=200,
            json={'state': {
                'status': 'failed'
            }},
        )

        # populate db
        sessions = PaymentGatewaySessionFactory.create_batch(
            3,
            status=PaymentGatewaySessionStatus.STARTED,
            govuk_payment_id=factory.Iterator(govuk_payment_ids),
        )

        # make call
        refresh_pending_payment_gateway_sessions(age_check=0)

        # check result
        for session in sessions:
            session.refresh_from_db()

        assert requests_mock.call_count == 3
        assert sessions[0].status == PaymentGatewaySessionStatus.FAILED
        assert sessions[1].status == PaymentGatewaySessionStatus.STARTED
        assert sessions[2].status == PaymentGatewaySessionStatus.FAILED
 def test_404_if_session_belongs_to_another_order(self):
     """
     Test that if the payment gateway session belongs to another order,
     the endpoint returns 404.
     """
     orders = OrderWithAcceptedQuoteFactory.create_batch(2)
     sessions = PaymentGatewaySessionFactory.create_batch(
         2, order=factory.Iterator(orders))
     url = reverse(
         'api-v3:omis-public:payment-gateway-session:detail',
         kwargs={
             'public_token': orders[0].public_token,
             'pk': sessions[1].id,
         },
     )
     client = self.create_api_client(
         scope=Scope.public_omis_front_end,
         grant_type=Application.GRANT_CLIENT_CREDENTIALS,
     )
     response = client.get(url)
     assert response.status_code == status.HTTP_404_NOT_FOUND
    def test_create_cancels_other_ongoing_sessions(self, requests_mock):
        """
        Test that creating a new payment gateway session cancels
        the other ongoing sessions and GOV.UK payments.

        Given:
            - ongoing session 1
            - ongoing session 2
            - failed session 3

        Calling this endpoint should:
            - cancel GOV.UK payment related to session 1
            - update the payment gateway session 1 status to 'cancelled'

            - cancel GOV.UK payment related to session 2
            - update the payment gateway session 2 status to 'cancelled'

            - start a new GOV.UK payment
            - create a payment gateway session related to it
        """
        order = OrderWithAcceptedQuoteFactory()
        existing_data = PaymentGatewaySessionFactory.create_batch(
            3,
            order=order,
            status=factory.Iterator([
                PaymentGatewaySessionStatus.created,
                PaymentGatewaySessionStatus.started,
                PaymentGatewaySessionStatus.failed,
            ]),
        )

        # mock GOV.UK requests used to:
        # - refresh the payment gateway sessions
        # - cancel the GOV.UK payments
        # - refresh the payment gateway sessions again after the cancellation
        for session in existing_data:
            requests_mock.get(
                govuk_url(f'payments/{session.govuk_payment_id}'),
                [
                    # this is for the initial refresh
                    {
                        'status_code': 200,
                        'json': {
                            'state': {
                                'status': session.status
                            }
                        },
                    },
                    # this is for the second refresh after cancelling
                    {
                        'status_code': 200,
                        'json': {
                            'state': {
                                'status': 'cancelled'
                            }
                        },
                    },
                ],
            )
            requests_mock.post(
                govuk_url(f'payments/{session.govuk_payment_id}/cancel'),
                status_code=204,
            )

        # mock GOV.UK call used to create a new payment session
        govuk_payment_id = '123abc123abc123abc123abc12'
        next_url = 'https://payment.example.com/123abc'
        json_response = {
            'state': {
                'status': 'created',
                'finished': False
            },
            'payment_id': govuk_payment_id,
            '_links': {
                'next_url': {
                    'href': next_url,
                    'method': 'GET',
                },
            },
        }
        requests_mock.post(
            govuk_url('payments'),  # create payment
            status_code=201,
            json=json_response,
        )
        requests_mock.get(
            govuk_url(f'payments/{govuk_payment_id}'),  # get payment
            status_code=200,
            json=json_response,
        )

        # make API call
        url = reverse(
            'api-v3:omis-public:payment-gateway-session:collection',
            kwargs={'public_token': order.public_token},
        )
        client = self.create_api_client(
            scope=Scope.public_omis_front_end,
            grant_type=Application.GRANT_CLIENT_CREDENTIALS,
        )
        response = client.post(url)
        assert response.status_code == status.HTTP_201_CREATED

        # check sessions cancelled
        for existing_session in existing_data[:-1]:
            existing_session.refresh_from_db()
            assert existing_session.status == PaymentGatewaySessionStatus.cancelled

        # check session record created
        assert PaymentGatewaySession.objects.ongoing().count() == 1
        session = PaymentGatewaySession.objects.ongoing().first()
        assert session.govuk_payment_id == govuk_payment_id

        # check API response
        assert response.json() == {
            'id': str(session.id),
            'created_on': format_date_or_datetime(session.created_on),
            'status': PaymentGatewaySessionStatus.created,
            'payment_url': next_url,
        }
Beispiel #6
0
    def test_create_cancels_other_sessions(self, requests_mock):
        """
        Test that creating a new payment gateway session cancels
        the other ongoing sessions and GOV.UK payments.

        Given:
            - ongoing session 1
            - ongoing session 2
            - failed session 3

        Calling .create_from_order should:
            - cancel the GOV.UK payment related to session 1
            - update the payment gateway session 1 status to 'cancelled'

            - cancel the GOV.UK payment related to session 2
            - update the payment gateway session 2 status to 'cancelled'

            - start a new GOV.UK payment
            - create a payment gateway session related to it
        """
        order = OrderWithAcceptedQuoteFactory()
        existing_data = PaymentGatewaySessionFactory.create_batch(
            3,
            order=order,
            status=factory.Iterator([
                PaymentGatewaySessionStatus.CREATED,
                PaymentGatewaySessionStatus.STARTED,
                PaymentGatewaySessionStatus.FAILED,
            ]),
        )

        # mock GOV.UK requests used to:
        # - refresh the payment gateway sessions
        # - cancel the GOV.UK payments
        # - refresh the payment gateway sessions again after the cancellation
        for session in existing_data:
            requests_mock.get(
                govuk_url(f'payments/{session.govuk_payment_id}'),
                [
                    # this is for the initial refresh
                    {
                        'status_code': 200,
                        'json': {'state': {'status': session.status}},
                    },
                    # this is for the second refresh after cancelling
                    {
                        'status_code': 200,
                        'json': {'state': {'status': 'cancelled'}},
                    },
                ],
            )
            requests_mock.post(
                govuk_url(f'payments/{session.govuk_payment_id}/cancel'),
                status_code=204,
            )

        # mock GOV.UK request used to create a new payment session
        govuk_payment_id = '123abc123abc123abc123abc12'
        requests_mock.post(
            govuk_url('payments'),
            status_code=201,
            json={
                'state': {'status': 'created', 'finished': False},
                'payment_id': govuk_payment_id,
                '_links': {
                    'next_url': {
                        'href': 'https://payment.example.com/123abc',
                        'method': 'GET',
                    },
                },
            },
        )

        assert PaymentGatewaySession.objects.count() == 3

        session = PaymentGatewaySession.objects.create_from_order(order=order)

        # check sessions cancelled
        for existing_session in existing_data[:-1]:
            existing_session.refresh_from_db()
            assert existing_session.status == PaymentGatewaySessionStatus.CANCELLED

        assert PaymentGatewaySession.objects.count() == 4

        # check session record created
        session.refresh_from_db()
        assert session.govuk_payment_id == govuk_payment_id

        # check mocked requests:
        #   2 refresh / 2 cancel - 2 refresh / 1 create
        assert requests_mock.call_count == (2 + 2 + 2 + 1)
        assert requests_mock.request_history[-1].json() == {
            'amount': order.total_cost,
            'reference': f'{order.reference}-{str(session.id)[:8].upper()}',
            'description': settings.GOVUK_PAY_PAYMENT_DESCRIPTION.format(
                reference=order.reference,
            ),
            'return_url': settings.GOVUK_PAY_RETURN_URL.format(
                public_token=order.public_token,
                session_id=session.id,
            ),
        }