diff --git a/README.md b/README.md index f3be5db1a..cca5660fe 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,6 @@ Brew is a package manager for OSX. The following command installs brew: Languages needed - Python 3.4 -- [pip] (https://pip.pypa.io/en/stable/installing/) - [Node](https://nodejs.org/) 5.0.0 or greater - [npm](https://www.npmjs.com/) 3.0.0 or greater ```shell @@ -35,7 +34,7 @@ different versions of Node. The following installs `n` and uses the latest version of Node. ```shell npm install -g n - sudo n latest + n latest npm rebuild node-sass ``` diff --git a/app/__init__.py b/app/__init__.py index a2c3047ed..f51b12b49 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -55,6 +55,7 @@ from app.notify_client.organisations_client import OrganisationsClient from app.notify_client.models import AnonymousUser from app.notify_client.letter_jobs_client import LetterJobsClient from app.notify_client.inbound_number_client import InboundNumberClient +from app.notify_client.billing_api_client import BillingAPIClient from app.utils import get_cdn_domain from app.utils import gmt_timezones @@ -77,6 +78,7 @@ asset_fingerprinter = AssetFingerprinter() statsd_client = StatsdClient() letter_jobs_client = LetterJobsClient() inbound_number_client = InboundNumberClient() +billing_api_client = BillingAPIClient() # The current service attached to the request stack. current_service = LocalProxy(partial(_lookup_req_object, 'service')) @@ -110,6 +112,7 @@ def create_app(): organisations_client.init_app(application) letter_jobs_client.init_app(application) inbound_number_client.init_app(application) + billing_api_client.init_app(application) login_manager.init_app(application) login_manager.login_view = 'main.sign_in' diff --git a/app/main/views/dashboard.py b/app/main/views/dashboard.py index 992902115..81c15790a 100644 --- a/app/main/views/dashboard.py +++ b/app/main/views/dashboard.py @@ -15,6 +15,7 @@ from notifications_utils.recipients import format_phone_number_human_readable from app.main import main from app import ( current_service, + billing_api_client, job_api_client, service_api_client, template_statistics_client @@ -105,10 +106,11 @@ def template_history(service_id): @user_has_permissions('manage_settings', admin_override=True) def usage(service_id): year, current_financial_year = requested_and_current_financial_year(request) + return render_template( 'views/usage.html', months=list(get_free_paid_breakdown_for_billable_units( - year, service_api_client.get_billable_units(service_id, year) + year, billing_api_client.get_billable_units(service_id, year) )), selected_year=year, years=get_tuples_of_financial_years( @@ -116,7 +118,7 @@ def usage(service_id): start=current_financial_year - 1, end=current_financial_year + 1, ), - **calculate_usage(service_api_client.get_service_usage(service_id, year)) + **calculate_usage(billing_api_client.get_service_usage(service_id, year)) ) diff --git a/app/notify_client/billing_api_client.py b/app/notify_client/billing_api_client.py new file mode 100644 index 000000000..2041f74fe --- /dev/null +++ b/app/notify_client/billing_api_client.py @@ -0,0 +1,25 @@ +from app.notify_client import NotifyAdminAPIClient + + +class BillingAPIClient(NotifyAdminAPIClient): + # Fudge assert in the super __init__ so + # we can set those variables later. + def __init__(self): + super().__init__("a" * 73, "b") + + def init_app(self, application): + self.base_url = application.config['API_HOST_NAME'] + self.service_id = application.config['ADMIN_CLIENT_USER_NAME'] + self.api_key = application.config['ADMIN_CLIENT_SECRET'] + + def get_billable_units(self, service_id, year): + return self.get( + '/service/{0}/billing/monthly-usage'.format(service_id), + params=dict(year=year) + ) + + def get_service_usage(self, service_id, year=None): + return self.get( + '/service/{0}/billing/yearly-usage-summary'.format(service_id), + params=dict(year=year) + ) diff --git a/app/notify_client/service_api_client.py b/app/notify_client/service_api_client.py index 2173e3402..dc84afb40 100644 --- a/app/notify_client/service_api_client.py +++ b/app/notify_client/service_api_client.py @@ -228,12 +228,6 @@ class ServiceAPIClient(NotifyAdminAPIClient): def get_service_history(self, service_id): return self.get('/service/{0}/history'.format(service_id)) - def get_service_usage(self, service_id, year=None): - return self.get( - '/service/{0}/yearly-usage'.format(service_id), - params=dict(year=year) - ) - def get_yearly_sms_unit_count_and_cost(self, service_id, year=None): return self.get( '/service/{0}/yearly-sms-billable-units'.format(service_id), @@ -249,12 +243,6 @@ class ServiceAPIClient(NotifyAdminAPIClient): def update_whitelist(self, service_id, data): return self.put(url='/service/{}/whitelist'.format(service_id), data=data) - def get_billable_units(self, service_id, year): - return self.get( - '/service/{0}/monthly-usage'.format(service_id), - params=dict(year=year) - ) - def get_inbound_sms(self, service_id, user_number=''): return self.get( '/service/{}/inbound-sms?user_number={}'.format( diff --git a/app/templates/views/integration_testing.html b/app/templates/views/integration_testing.html index 53dd64eb0..b16855cff 100644 --- a/app/templates/views/integration_testing.html +++ b/app/templates/views/integration_testing.html @@ -50,6 +50,12 @@

You should revoke and re-create these keys on a regular basis. You can have more than one active key at a time. To revoke a key click the revoke button on the API Key page.

+ +
+

+ You should never send test messages to invalid numbers or addresses using a live key. This will lead to your API key being revoked. +

+

Team and whitelist key

diff --git a/app/templates/views/signedout.html b/app/templates/views/signedout.html index fccfe6654..175e7bbdb 100644 --- a/app/templates/views/signedout.html +++ b/app/templates/views/signedout.html @@ -117,12 +117,12 @@

Services

-
70
+
71
services

Departments

-
34
+
35
departments
diff --git a/requirements_for_test.txt b/requirements_for_test.txt index 393bacdf4..53c15da19 100644 --- a/requirements_for_test.txt +++ b/requirements_for_test.txt @@ -3,8 +3,8 @@ pycodestyle==2.3.1 pytest==3.2.1 pytest-mock==1.6.2 pytest-cov==2.5.1 -pytest-xdist==1.19.1 -coveralls==1.1 +pytest-xdist==1.20.0 +coveralls==1.2.0 moto==1.0.1 httpretty==0.8.14 beautifulsoup4==4.6.0 diff --git a/tests/app/notify_client/test_billing_client.py b/tests/app/notify_client/test_billing_client.py new file mode 100644 index 000000000..250ad24cd --- /dev/null +++ b/tests/app/notify_client/test_billing_client.py @@ -0,0 +1,27 @@ +import uuid + +from app.notify_client.billing_api_client import BillingAPIClient + + +def test_get_billing_units_calls_correct_endpoint(mocker, api_user_active): + service_id = uuid.uuid4() + expected_url = '/service/{}/billing/monthly-usage'.format(service_id) + + client = BillingAPIClient() + + mock_get = mocker.patch('app.notify_client.billing_api_client.BillingAPIClient.get') + + client.get_billable_units(service_id, 2017) + mock_get.assert_called_once_with(expected_url, params={'year': 2017}) + + +def test_get_get_service_usage_calls_correct_endpoint(mocker, api_user_active): + service_id = uuid.uuid4() + expected_url = '/service/{}/billing/yearly-usage-summary'.format(service_id) + + client = BillingAPIClient() + + mock_get = mocker.patch('app.notify_client.billing_api_client.BillingAPIClient.get') + + client.get_service_usage(service_id, 2017) + mock_get.assert_called_once_with(expected_url, params={'year': 2017}) diff --git a/tests/conftest.py b/tests/conftest.py index af6752f8d..b16bbb145 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1505,7 +1505,7 @@ def mock_get_usage(mocker, service_one, fake_uuid): ] return mocker.patch( - 'app.service_api_client.get_service_usage', side_effect=_get_usage) + 'app.billing_api_client.get_service_usage', side_effect=_get_usage) @pytest.fixture(scope='function') @@ -1605,7 +1605,7 @@ def mock_get_billable_units(mocker): ] return mocker.patch( - 'app.service_api_client.get_billable_units', side_effect=_get_usage) + 'app.billing_api_client.get_billable_units', side_effect=_get_usage) @pytest.fixture(scope='function') @@ -1623,7 +1623,7 @@ def mock_get_future_usage(mocker, service_one, fake_uuid): ] return mocker.patch( - 'app.service_api_client.get_service_usage', side_effect=_get_usage) + 'app.billing_api_client.get_service_usage', side_effect=_get_usage) @pytest.fixture(scope='function') @@ -1632,7 +1632,7 @@ def mock_get_future_billable_units(mocker): return [] return mocker.patch( - 'app.service_api_client.get_billable_units', side_effect=_get_usage) + 'app.billing_api_client.get_billable_units', side_effect=_get_usage) @pytest.fixture(scope='function')