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
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, }
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, ), }