示例#1
0
    def test_notify_on_order_paid(self):
        """Test that a notification is triggered when an order is marked as paid."""
        order = OrderWithAcceptedQuoteFactory(assignees=[])
        OrderAssigneeFactory.create_batch(1, order=order)
        OrderSubscriberFactory.create_batch(2, order=order)

        notify.client.reset_mock()

        order.mark_as_paid(
            by=AdviserFactory(),
            payments_data=[
                {
                    'amount': order.total_cost,
                    'received_on': dateutil_parse('2017-01-02').date(),
                },
            ],
        )

        #  1 = customer, 3 = assignees/subscribers
        assert len(
            notify.client.send_email_notification.call_args_list) == (3 + 1)

        templates_called = [
            data[1]['template_id']
            for data in notify.client.send_email_notification.call_args_list
        ]
        assert templates_called == [
            Template.order_paid_for_customer.value,
            Template.order_paid_for_adviser.value,
            Template.order_paid_for_adviser.value,
            Template.order_paid_for_adviser.value,
        ]
示例#2
0
    def test_ok_if_amounts_greater_than_total_cost(self):
        """
        Test that if the sum of the amounts is greater than order.total_cost,
        the reconciliation is successful.
        """
        order = OrderWithAcceptedQuoteFactory()

        url = reverse('api-v3:omis:payment:collection',
                      kwargs={'order_pk': order.pk})
        response = self.api_client.post(
            url,
            [
                {
                    'amount': order.total_cost,
                    'method': PaymentMethod.bacs,
                    'received_on': '2017-04-20',
                },
                {
                    'amount': 1,
                    'method': PaymentMethod.bacs,
                    'received_on': '2017-04-21',
                },
            ],
        )
        assert response.status_code == status.HTTP_201_CREATED
示例#3
0
    def test_exception_if_govuk_pay_errors_when_creating(
        self, govuk_status_code, requests_mock,
    ):
        """
        Test that if GOV.UK Pay errors whilst creating a new payment, the method raises
        GOVUKPayAPIException.

        Possible GOV.UK Pay errors:
        - 400 - BAD REQUEST
        - 401 - UNAUTHORIZED
        - 422 - UNPROCESSABLE ENTITY
        - 500 - INTERNAL SERVER ERROR
        """
        requests_mock.post(
            govuk_url('payments'),
            status_code=govuk_status_code,
        )

        assert PaymentGatewaySession.objects.count() == 0

        order = OrderWithAcceptedQuoteFactory()

        with pytest.raises(GOVUKPayAPIException):
            PaymentGatewaySession.objects.create_from_order(order)

        assert PaymentGatewaySession.objects.count() == 0
    def test_500_if_govuk_pay_errors(self, govuk_status_code, requests_mock):
        """
        Test that if GOV.UK Pay errors whilst getting a payment, the endpoint returns 500.

        Possible GOV.UK errors:
        - 401 - UNAUTHORIZED
        - 404 - NOT FOUND
        - 500 - INTERNAL SERVER ERROR
        """
        order = OrderWithAcceptedQuoteFactory()
        session = PaymentGatewaySessionFactory(
            order=order,
            status=PaymentGatewaySessionStatus.created,
        )

        requests_mock.get(
            govuk_url(f'payments/{session.govuk_payment_id}'),
            status_code=govuk_status_code,
        )

        # make API call
        url = reverse(
            'api-v3:omis-public:payment-gateway-session:detail',
            kwargs={
                'public_token': order.public_token,
                'pk': session.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_500_INTERNAL_SERVER_ERROR
示例#5
0
    def test_create_first_session_from_order(self, requests_mock, monkeypatch):
        """
        Test the successful creation of the first payment gateway session for an order.
        """
        monkeypatch.setattr(
            'uuid.uuid4',
            mock.Mock(return_value='0123abcd-0000-0000-0000-000000000000'),
        )

        # mock request
        govuk_payment_id = '123abc123abc123abc123abc12'
        govuk_payments_url = govuk_url('payments')
        requests_mock.post(
            govuk_payments_url,
            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() == 0

        # call method
        adviser = AdviserFactory()
        order = OrderWithAcceptedQuoteFactory()
        session = PaymentGatewaySession.objects.create_from_order(
            order=order,
            attrs={'created_by': adviser},
        )

        # check session
        assert session.order == order
        assert session.status == PaymentGatewaySessionStatus.CREATED
        assert session.govuk_payment_id == govuk_payment_id
        assert session.created_by == adviser

        assert PaymentGatewaySession.objects.count() == 1

        # check mocked request
        assert requests_mock.call_count == 1
        assert requests_mock.request_history[-1].url == govuk_payments_url
        assert requests_mock.request_history[-1].json() == {
            'amount': order.total_cost,
            'reference': f'{order.reference}-0123ABCD',
            '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.pk,
            ),
        }
示例#6
0
    def test_verbs_not_allowed(self, verb, public_omis_api_client):
        """Test that makes sure the other verbs are not allowed."""
        order = OrderWithAcceptedQuoteFactory()

        url = reverse(
            'api-v3:public-omis:invoice:detail',
            kwargs={'public_token': order.public_token},
        )
        response = getattr(public_omis_api_client, verb)(url, json_={})
        assert response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED
 def test_verbs_not_allowed(self, verb_kwargs, public_omis_api_client):
     """Test that makes sure the other verbs are not allowed."""
     order = OrderWithAcceptedQuoteFactory()
     verb, kwargs = verb_kwargs
     url = reverse(
         'api-v3:public-omis:payment-gateway-session:collection',
         kwargs={'public_token': order.public_token},
     )
     response = getattr(public_omis_api_client, verb)(url, **kwargs)
     assert response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED
    def test_429_if_too_many_requests_made(
        self,
        local_memory_cache,
        requests_mock,
        monkeypatch,
        public_omis_api_client,
    ):
        """Test that the throttling for the create endpoint works if its rate is set."""
        monkeypatch.setitem(
            settings.REST_FRAMEWORK['DEFAULT_THROTTLE_RATES'],
            'payment_gateway_session.create',
            '3/sec',
        )

        # mock GOV.UK response
        govuk_payment_id = '123abc123abc123abc123abc12'
        json_response = {
            'state': {'status': 'created', 'finished': False},
            'payment_id': govuk_payment_id,
            '_links': {
                'next_url': {
                    'href': 'https://payment.example.com/123abc',
                    '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,
        )
        requests_mock.post(
            govuk_url(f'payments/{govuk_payment_id}/cancel'),  # cancel payment
            status_code=204,
        )

        order = OrderWithAcceptedQuoteFactory()

        url = reverse(
            'api-v3:public-omis:payment-gateway-session:collection',
            kwargs={'public_token': order.public_token},
        )

        # the 4th time it should error
        for _ in range(3):
            response = public_omis_api_client.post(url, json_={})
            assert response.status_code == status.HTTP_201_CREATED

        response = public_omis_api_client.post(url, json_={})
        assert response.status_code == status.HTTP_429_TOO_MANY_REQUESTS
    def test_create_first_session(self, requests_mock, public_omis_api_client):
        """
        Test a successful call to create a payment gateway session.

        This starts a GOV.UK payment and creates an OMIS payment gateway session
        object tracking it.
        """
        # mock GOV.UK response
        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,
        )

        assert PaymentGatewaySession.objects.count() == 0

        # make API call
        order = OrderWithAcceptedQuoteFactory()
        url = reverse(
            'api-v3:public-omis:payment-gateway-session:collection',
            kwargs={'public_token': order.public_token},
        )
        response = public_omis_api_client.post(url, json_={})
        assert response.status_code == status.HTTP_201_CREATED

        # check payment gateway session record created
        assert PaymentGatewaySession.objects.count() == 1
        session = PaymentGatewaySession.objects.first()
        assert session.govuk_payment_id == govuk_payment_id
        assert session.status == PaymentGatewaySessionStatus.CREATED

        # 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_500_if_govuk_pay_errors_when_cancelling(self, govuk_status_code,
                                                     requests_mock):
        """
        Test that if GOV.UK Pay errors whilst cancelling some other ongoing
        sessions/payments, the endpoint returns 500 to keep the system consistent.

        Possible GOV.UK errors when cancelling:
        - 400 - BAD REQUEST
        - 401 - UNAUTHORIZED
        - 404 - NOT FOUND
        - 409 - CONFLICT
        - 500 - INTERNAL SERVER ERROR

        In all these cases we return 500 as all those GOV.UK errors are unexpected.
        """
        order = OrderWithAcceptedQuoteFactory()
        existing_session = PaymentGatewaySessionFactory(
            order=order,
            status=PaymentGatewaySessionStatus.created,
        )

        # mock GOV.UK requests used to
        # - refresh the existing payment gateway session
        # - cancel the GOV.UK payment
        requests_mock.get(
            govuk_url(f'payments/{existing_session.govuk_payment_id}'),
            status_code=200,
            json={
                'state': {
                    'status': existing_session.status
                },
            },
        )
        requests_mock.post(
            govuk_url(f'payments/{existing_session.govuk_payment_id}/cancel'),
            status_code=govuk_status_code,
        )

        # make API call
        assert PaymentGatewaySession.objects.count() == 1

        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_500_INTERNAL_SERVER_ERROR

        # check no session created
        assert PaymentGatewaySession.objects.count() == 1
    def test_verbs_not_allowed(self, verb, public_omis_api_client):
        """Test that makes sure the other verbs are not allowed."""
        order = OrderWithAcceptedQuoteFactory()
        session = PaymentGatewaySessionFactory(order=order)

        url = reverse(
            'api-v3:public-omis:payment-gateway-session:detail',
            kwargs={'public_token': order.public_token, 'pk': session.id},
        )
        response = getattr(public_omis_api_client, verb)(url, json_={})
        assert response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED
示例#12
0
def setup_data(setup_es):
    """Sets up data for the tests."""
    with freeze_time('2017-01-01 13:00:00'):
        company = CompanyFactory(name='Mercury trading', alias='Uranus supplies')
        contact = ContactFactory(company=company, first_name='John', last_name='Doe')
        order = OrderFactory(
            reference='abcd',
            primary_market_id=constants.Country.japan.value.id,
            uk_region_id=constants.UKRegion.channel_islands.value.id,
            assignees=[],
            status=OrderStatus.draft,
            company=company,
            contact=contact,
            discount_value=0,
            delivery_date=dateutil_parse('2018-01-01').date(),
            vat_verified=False,
        )
        OrderSubscriberFactory(
            order=order,
            adviser=AdviserFactory(dit_team_id=constants.Team.healthcare_uk.value.id),
        )
        OrderAssigneeFactory(
            order=order,
            adviser=AdviserFactory(dit_team_id=constants.Team.tees_valley_lep.value.id),
            estimated_time=60,
        )

    with freeze_time('2017-02-01 13:00:00'):
        company = CompanyFactory(name='Venus Ltd', alias='Earth outsourcing')
        contact = ContactFactory(company=company, first_name='Jenny', last_name='Cakeman')
        order = OrderWithAcceptedQuoteFactory(
            reference='efgh',
            primary_market_id=constants.Country.france.value.id,
            uk_region_id=constants.UKRegion.east_midlands.value.id,
            assignees=[],
            status=OrderStatus.quote_awaiting_acceptance,
            company=company,
            contact=contact,
            discount_value=0,
            delivery_date=dateutil_parse('2018-02-01').date(),
            vat_verified=False,
        )
        OrderSubscriberFactory(
            order=order,
            adviser=AdviserFactory(dit_team_id=constants.Team.td_events_healthcare.value.id),
        )
        OrderAssigneeFactory(
            order=order,
            adviser=AdviserFactory(dit_team_id=constants.Team.food_from_britain.value.id),
            estimated_time=120,
        )

        setup_es.indices.refresh()
 def test_404_if_session_doesnt_exist(self, public_omis_api_client):
     """Test that if the payment gateway session doesn't exist, the endpoint returns 404."""
     order = OrderWithAcceptedQuoteFactory()
     url = reverse(
         'api-v3:public-omis:payment-gateway-session:detail',
         kwargs={
             'public_token': order.public_token,
             'pk': '00000000-0000-0000-0000-000000000000',
         },
     )
     response = public_omis_api_client.get(url)
     assert response.status_code == status.HTTP_404_NOT_FOUND
示例#14
0
    def test_404_if_in_disallowed_status(self, order_status,
                                         public_omis_api_client):
        """Test that if the order is not in an allowed state, the endpoint returns 404."""
        order = OrderWithAcceptedQuoteFactory(status=order_status)

        url = reverse(
            'api-v3:public-omis:invoice:detail',
            kwargs={'public_token': order.public_token},
        )
        response = public_omis_api_client.get(url)

        assert response.status_code == status.HTTP_404_NOT_FOUND
    def test_403_if_scope_not_allowed(self, scope):
        """Test that other oauth2 scopes are not allowed."""
        order = OrderWithAcceptedQuoteFactory()

        url = reverse(
            'api-v3:omis-public:payment-gateway-session:collection',
            kwargs={'public_token': order.public_token},
        )
        client = self.create_api_client(
            scope=scope,
            grant_type=Application.GRANT_CLIENT_CREDENTIALS,
        )
        response = client.post(url)
        assert response.status_code == status.HTTP_403_FORBIDDEN
    def test_verbs_not_allowed(self, verb):
        """Test that makes sure the other verbs are not allowed."""
        order = OrderWithAcceptedQuoteFactory()

        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 = getattr(client, verb)(url)
        assert response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED
示例#17
0
    def test_404_if_in_disallowed_status(self, order_status):
        """Test that if the order is not in an allowed state, the endpoint returns 404."""
        order = OrderWithAcceptedQuoteFactory(status=order_status)

        url = reverse(
            'api-v3:omis-public:invoice:detail',
            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.get(url)

        assert response.status_code == status.HTTP_404_NOT_FOUND
示例#18
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
示例#20
0
    def test_get(self):
        """Test a successful call to get a invoice."""
        order = OrderWithAcceptedQuoteFactory()
        invoice = order.invoice

        url = reverse('api-v3:omis:invoice:detail',
                      kwargs={'order_pk': order.pk})
        response = self.api_client.get(url)

        assert response.status_code == status.HTTP_200_OK
        assert response.json() == {
            'created_on': format_date_or_datetime(invoice.created_on),
            'invoice_number': invoice.invoice_number,
            'invoice_company_name': invoice.invoice_company_name,
            'invoice_address_1': invoice.invoice_address_1,
            'invoice_address_2': invoice.invoice_address_2,
            'invoice_address_county': invoice.invoice_address_county,
            'invoice_address_town': invoice.invoice_address_town,
            'invoice_address_postcode': invoice.invoice_address_postcode,
            'invoice_address_country': {
                'id': str(invoice.invoice_address_country.pk),
                'name': invoice.invoice_address_country.name,
            },
            'invoice_vat_number': invoice.invoice_vat_number,
            'payment_due_date': invoice.payment_due_date.isoformat(),
            'billing_contact_name': invoice.billing_contact_name,
            'billing_company_name': invoice.billing_company_name,
            'billing_address_1': invoice.billing_address_1,
            'billing_address_2': invoice.billing_address_2,
            'billing_address_county': invoice.billing_address_county,
            'billing_address_postcode': invoice.billing_address_postcode,
            'billing_address_town': invoice.billing_address_town,
            'billing_address_country': {
                'id': str(invoice.billing_address_country.pk),
                'name': invoice.billing_address_country.name,
            },
            'po_number': invoice.po_number,
            'vat_status': invoice.vat_status,
            'vat_number': invoice.vat_number,
            'vat_verified': invoice.vat_verified,
            'net_cost': invoice.net_cost,
            'subtotal_cost': invoice.subtotal_cost,
            'vat_cost': invoice.vat_cost,
            'total_cost': invoice.total_cost,
        }
示例#21
0
    def test_first_invoice_number_of_the_day(self):
        """Test that the first invoice number of the day is generated as expected."""
        # create some in different months/days
        dts = (
            '2017-01-01 13:00:00',
            '2017-03-01 13:00:00',
            '2016-02-01 13:00:00',
            '2018-02-01 13:00:00',
        )
        for dt in dts:
            with freeze_time(dt):
                OrderWithAcceptedQuoteFactory()
        assert Invoice.objects.count() == 4

        with freeze_time('2017-02-01 13:00:00'):
            invoice_number = generate_datetime_based_reference(Invoice, field='invoice_number')

        assert invoice_number == '201702010001'
示例#22
0
    def test_exception_if_govuk_pay_errors_when_cancelling(
        self, govuk_status_code, requests_mock,
    ):
        """
        Test that if GOV.UK Pay errors whilst cancelling some other ongoing
        sessions/payments, the method raises GOVUKPayAPIException to keep the system consistent.

        Possible GOV.UK Pay errors when cancelling:
        - 400 - BAD REQUEST
        - 401 - UNAUTHORIZED
        - 404 - NOT FOUND
        - 409 - CONFLICT
        - 500 - INTERNAL SERVER ERROR
        """
        order = OrderWithAcceptedQuoteFactory()
        existing_session = PaymentGatewaySessionFactory(
            order=order,
            status=PaymentGatewaySessionStatus.CREATED,
        )

        # mock GOV.UK requests used to
        # - refresh the existing payment gateway session
        # - cancel the GOV.UK payment
        requests_mock.get(
            govuk_url(f'payments/{existing_session.govuk_payment_id}'),
            status_code=200,
            json={
                'state': {'status': existing_session.status},
            },
        )
        requests_mock.post(
            govuk_url(f'payments/{existing_session.govuk_payment_id}/cancel'),
            status_code=govuk_status_code,
        )

        assert PaymentGatewaySession.objects.count() == 1

        with pytest.raises(GOVUKPayAPIException):
            PaymentGatewaySession.objects.create_from_order(order)

        assert PaymentGatewaySession.objects.count() == 1
    def test_500_if_govuk_pay_errors_when_creating(self, govuk_status_code,
                                                   requests_mock):
        """
        Test that if GOV.UK Pay errors whilst creating a new payment, the endpoint returns 500.

        Possible GOV.UK errors:
        - 400 - BAD REQUEST
        - 401 - UNAUTHORIZED
        - 422 - UNPROCESSABLE ENTITY
        - 500 - INTERNAL SERVER ERROR

        In all these cases we return 500 as all those GOV.UK errors are unexpected.
        """
        # mock GOV.UK response
        requests_mock.post(
            govuk_url('payments'),
            status_code=govuk_status_code,
        )

        assert PaymentGatewaySession.objects.count() == 0

        # make API call
        order = OrderWithAcceptedQuoteFactory()
        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_500_INTERNAL_SERVER_ERROR

        # check no session created
        assert PaymentGatewaySession.objects.count() == 0