diff --git a/app/billing/billing_schemas.py b/app/billing/billing_schemas.py new file mode 100644 index 000000000..f9f592e7d --- /dev/null +++ b/app/billing/billing_schemas.py @@ -0,0 +1,14 @@ +from app.schema_validation.definitions import uuid, https_url + + +create_or_update_free_sms_fragment_limit_schema = { + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "POST annual billing schema", + "type": "object", + "title": "Create", + "properties": { + "free_sms_fragment_limit": {"type": "integer", "minimum": 1}, + "financial_year_start": {"type": "integer", "minimum": 2016} + }, + "required": ["free_sms_fragment_limit", "financial_year_start"] +} diff --git a/app/billing/rest.py b/app/billing/rest.py index 197adadf2..a29e31be7 100644 --- a/app/billing/rest.py +++ b/app/billing/rest.py @@ -11,6 +11,14 @@ from app.dao.date_util import get_financial_year, get_months_for_financial_year from app.errors import register_errors from app.models import SMS_TYPE, EMAIL_TYPE from app.utils import convert_utc_to_bst +from app.dao.annual_billing_dao import (dao_get_free_sms_fragment_limit_for_year, + dao_get_all_free_sms_fragment_limit, + dao_create_or_update_annual_billing_for_year) +from app.billing.billing_schemas import create_or_update_free_sms_fragment_limit_schema +from app.errors import InvalidRequest +from app.schema_validation import validate +from app.models import AnnualBilling +from app.service.utils import get_current_financial_year_start_year billing_blueprint = Blueprint( 'billing', @@ -86,3 +94,52 @@ def _transform_billing_for_month(billing_for_month): "notification_type": billing_for_month.notification_type, "rate": rate } + + +@billing_blueprint.route('/free-sms-fragment-limit', methods=["GET"]) +@billing_blueprint.route('/free-sms-fragment-limit/current-year', methods=["GET"]) +def get_free_sms_fragment_limit(service_id): + + if request.path.split('/')[-1] == 'current-year': + financial_year_start = get_current_financial_year_start_year() + else: + financial_year_start = request.args.get('financial_year_start') + + if financial_year_start is None: + results = dao_get_all_free_sms_fragment_limit(service_id) + + if len(results) == 0: + raise InvalidRequest('no annual billing information for this service', status_code=404) + return jsonify(data=[row.serialize_free_sms_items() for row in results]), 200 + else: + result = dao_get_free_sms_fragment_limit_for_year(service_id, financial_year_start) + if result is None: + raise InvalidRequest('no free-sms-fragment-limit-info for this service and year', status_code=404) + + return jsonify(data=result.serialize_free_sms_items()), 200 + + +@billing_blueprint.route('/free-sms-fragment-limit', methods=["POST"]) +def create_or_update_free_sms_fragment_limit(service_id): + + dict_arg = request.get_json() + + if 'financial_year_start' not in dict_arg: + dict_arg['financial_year_start'] = get_current_financial_year_start_year() + + form = validate(dict_arg, create_or_update_free_sms_fragment_limit_schema) + + financial_year_start = form.get('financial_year_start') + free_sms_fragment_limit = form.get('free_sms_fragment_limit') + + result = dao_get_free_sms_fragment_limit_for_year(service_id, financial_year_start) + + if result: + result.free_sms_fragment_limit = free_sms_fragment_limit + else: + result = AnnualBilling(service_id=service_id, financial_year_start=financial_year_start, + free_sms_fragment_limit=free_sms_fragment_limit) + + dao_create_or_update_annual_billing_for_year(result) + + return jsonify(data=form), 201 diff --git a/app/celery/tasks.py b/app/celery/tasks.py index abafa6b78..b5e732df5 100644 --- a/app/celery/tasks.py +++ b/app/celery/tasks.py @@ -555,7 +555,10 @@ def process_incomplete_job(job_id): @notify_celery.task(bind=True, name="process-ses-result", max_retries=5, default_retry_delay=300) @statsd(namespace="tasks") def process_ses_results(self, response): - errors = process_ses_response(response) - if errors: - current_app.logger.error(errors) + try: + errors = process_ses_response(response) + if errors: + current_app.logger.error(errors) + except Exception: + current_app.logger.exception('Error processing SES results') self.retry(queue=QueueNames.RETRY, exc="SES responses processed with error") diff --git a/app/dao/annual_billing_dao.py b/app/dao/annual_billing_dao.py new file mode 100644 index 000000000..2df3e1497 --- /dev/null +++ b/app/dao/annual_billing_dao.py @@ -0,0 +1,47 @@ +from app import db, create_uuid +from app.dao.dao_utils import ( + transactional, + version_class +) +from app.models import AnnualBilling +from datetime import datetime +from app.service.utils import get_current_financial_year_start_year + + +def dao_get_annual_billing(service_id): + return AnnualBilling.query.filter_by( + service_id=service_id, + ).order_by(AnnualBilling.financial_year_start).all() + + +def dao_create_or_update_annual_billing_for_year(annual_billing): + db.session.add(annual_billing) + db.session.commit() + + +def dao_get_free_sms_fragment_limit_for_year(service_id, year): + + return AnnualBilling.query.filter_by( + service_id=service_id, + financial_year_start=year + ).first() + + +def dao_get_all_free_sms_fragment_limit(service_id): + + return AnnualBilling.query.filter_by( + service_id=service_id, + ).order_by(AnnualBilling.financial_year_start).all() + + +def dao_insert_annual_billing(service): + """ + This method is called from create_service which is wrapped in a transaction. + """ + annual_billing = AnnualBilling( + free_sms_fragment_limit=service.free_sms_fragment_limit, + financial_year_start=get_current_financial_year_start_year(), + service=service, + ) + + db.session.add(annual_billing) diff --git a/app/dao/services_dao.py b/app/dao/services_dao.py index 986a0b7bb..b22c07e58 100644 --- a/app/dao/services_dao.py +++ b/app/dao/services_dao.py @@ -37,10 +37,12 @@ from app.models import ( EMAIL_TYPE, INTERNATIONAL_SMS_TYPE, ServiceSmsSender, + AnnualBilling ) from app.service.statistics import format_monthly_template_notification_stats from app.statsd_decorators import statsd from app.utils import get_london_month_from_utc_column, get_london_midnight_in_utc +from app.dao.annual_billing_dao import dao_insert_annual_billing DEFAULT_SERVICE_PERMISSIONS = [ SMS_TYPE, @@ -164,6 +166,9 @@ def dao_create_service(service, user, service_id=None, service_permissions=None) if service_permissions is None: service_permissions = DEFAULT_SERVICE_PERMISSIONS + if service.free_sms_fragment_limit is None: + service.free_sms_fragment_limit = current_app.config['FREE_SMS_TIER_FRAGMENT_COUNT'] + from app.dao.permissions_dao import permission_dao service.users.append(user) permission_dao.add_default_service_permissions_for_user(user, service) @@ -176,6 +181,7 @@ def dao_create_service(service, user, service_id=None, service_permissions=None) service.permissions.append(service_permission) insert_service_sms_sender(service, service.sms_sender) + dao_insert_annual_billing(service) db.session.add(service) @@ -238,6 +244,7 @@ def delete_service_and_all_associated_db_objects(service): _delete_commit(ServicePermission.query.filter_by(service_id=service.id)) _delete_commit(ApiKey.query.filter_by(service=service)) _delete_commit(ApiKey.get_history_model().query.filter_by(service_id=service.id)) + _delete_commit(AnnualBilling.query.filter_by(service_id=service.id)) verify_codes = VerifyCode.query.join(User).filter(User.id.in_([x.id for x in service.users])) list(map(db.session.delete, verify_codes)) diff --git a/app/models.py b/app/models.py index 614d3b5c6..4594616a6 100644 --- a/app/models.py +++ b/app/models.py @@ -187,27 +187,6 @@ class ServicePermissionTypes(db.Model): name = db.Column(db.String(255), primary_key=True) -class AnnualBilling(db.Model): - __tablename__ = "annual_billing" - id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, unique=False) - service_id = db.Column(UUID(as_uuid=True), db.ForeignKey('services.id'), unique=False, index=True, nullable=False) - financial_year_start = db.Column(db.Integer, nullable=False, default=True, unique=False) - free_sms_fragment_limit = db.Column(db.Integer, nullable=False, index=False, unique=False) - updated_at = db.Column(db.DateTime, nullable=True, onupdate=datetime.datetime.utcnow) - created_at = db.Column(db.DateTime, nullable=False, default=datetime.datetime.utcnow) - UniqueConstraint('financial_year_start', 'service_id', name='ix_annual_billing_service_id') - - def serialize(self): - return { - 'id': str(self.id), - 'service_id': str(self.service_id), - 'free_sms_fragment_limit': str(self.free_sms_fragment_limit), - 'financial_year_start': str(self.financial_year_start), - 'created_at': self.created_at.strftime(DATETIME_FORMAT), - 'updated_at': self.updated_at.strftime(DATETIME_FORMAT) if self.updated_at else None - } - - class Service(db.Model, Versioned): __tablename__ = 'services' @@ -242,7 +221,6 @@ class Service(db.Model, Versioned): organisation_id = db.Column(UUID(as_uuid=True), db.ForeignKey('organisation.id'), index=True, nullable=True) free_sms_fragment_limit = db.Column(db.BigInteger, index=False, unique=False, nullable=True) organisation = db.relationship('Organisation') - annual_billing = db.relationship('AnnualBilling') dvla_organisation_id = db.Column( db.String, db.ForeignKey('dvla_organisation.id'), @@ -297,6 +275,41 @@ class Service(db.Model, Versioned): return default_letter_contact[0].contact_block if default_letter_contact else None +class AnnualBilling(db.Model): + __tablename__ = "annual_billing" + id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, unique=False) + service_id = db.Column(UUID(as_uuid=True), db.ForeignKey('services.id'), unique=False, index=True, nullable=False) + financial_year_start = db.Column(db.Integer, nullable=False, default=True, unique=False) + free_sms_fragment_limit = db.Column(db.Integer, nullable=False, index=False, unique=False) + updated_at = db.Column(db.DateTime, nullable=True, onupdate=datetime.datetime.utcnow) + created_at = db.Column(db.DateTime, nullable=False, default=datetime.datetime.utcnow) + UniqueConstraint('financial_year_start', 'service_id', name='ix_annual_billing_service_id') + service = db.relationship(Service, backref=db.backref("annual_billing", uselist=True)) + + def serialize_free_sms_items(self): + return { + 'free_sms_fragment_limit': self.free_sms_fragment_limit, + 'financial_year_start': self.financial_year_start, + } + + def serialize(self): + def serialize_service(): + return { + "id": str(self.service_id), + "name": self.service.name + } + + return{ + "id": str(self.id), + 'free_sms_fragment_limit': self.free_sms_fragment_limit, + 'service_id': self.service_id, + 'financial_year_start': self.financial_year_start, + "created_at": self.created_at.strftime(DATETIME_FORMAT), + "updated_at": self.updated_at.strftime(DATETIME_FORMAT) if self.updated_at else None, + "service": serialize_service() if self.service else None, + } + + class InboundNumber(db.Model): __tablename__ = "inbound_numbers" diff --git a/app/service/rest.py b/app/service/rest.py index e7a2ce73f..c6e8c4201 100644 --- a/app/service/rest.py +++ b/app/service/rest.py @@ -73,7 +73,8 @@ from app.errors import ( InvalidRequest, register_errors ) -from app.models import Service, ServiceInboundApi + +from app.models import Service, ServiceInboundApi, AnnualBilling from app.schema_validation import validate from app.service import statistics from app.service.service_inbound_api_schema import ( @@ -168,8 +169,6 @@ def create_service(): raise InvalidRequest(errors, status_code=400) # TODO: to be removed when front-end is updated - if 'free_sms_fragment_limit' not in data: - data['free_sms_fragment_limit'] = current_app.config['FREE_SMS_TIER_FRAGMENT_COUNT'] # validate json with marshmallow service_schema.load(request.get_json()) diff --git a/app/service/utils.py b/app/service/utils.py index 2c4ccbf04..475d420e2 100644 --- a/app/service/utils.py +++ b/app/service/utils.py @@ -6,6 +6,8 @@ from app.models import ( KEY_TYPE_TEST, KEY_TYPE_TEAM, KEY_TYPE_NORMAL) from notifications_utils.recipients import allowed_to_send_to +from app.dao.notifications_dao import get_financial_year +from datetime import datetime def get_recipients_from_request(request_json, key, type): @@ -51,3 +53,12 @@ def service_allowed_to_send_to(recipient, service, key_type): whitelist_members ) ) + + +def get_current_financial_year_start_year(): + now = datetime.now() + financial_year_start = now.year + start_date, end_date = get_financial_year(now.year) + if now < start_date: + financial_year_start = financial_year_start - 1 + return financial_year_start diff --git a/tests/app/billing/test_billing.py b/tests/app/billing/test_billing.py index 8c1a6be8a..68175d704 100644 --- a/tests/app/billing/test_billing.py +++ b/tests/app/billing/test_billing.py @@ -15,6 +15,10 @@ from tests.app.db import ( from tests import create_authorization_header +from app.service.utils import get_current_financial_year_start_year + +import uuid + APR_2016_MONTH_START = datetime(2016, 3, 31, 23, 00, 00) APR_2016_MONTH_END = datetime(2016, 4, 30, 22, 59, 59, 99999) @@ -251,3 +255,145 @@ def test_transform_billing_calculates_with_different_rate_multipliers(sample_ser 'month': 'April', 'rate': 0.12, }) + + +def test_create_update_free_sms_fragment_limit_invalid_schema(client, sample_service): + + response = client.post('service/{}/billing/free-sms-fragment-limit'.format(sample_service.id), + data={}, + headers=[('Content-Type', 'application/json'), create_authorization_header()]) + json_resp = json.loads(response.get_data(as_text=True)) + + assert response.status_code == 400 + assert 'JSON' in json_resp['message'] + + +def test_create_free_sms_fragment_limit(client, sample_service): + + data = {'financial_year_start': 2017, 'free_sms_fragment_limit': 250} + response = client.post('service/{}/billing/free-sms-fragment-limit'.format(sample_service.id), + data=json.dumps(data), + headers=[('Content-Type', 'application/json'), create_authorization_header()]) + + response_get = client.get( + 'service/{}/billing/free-sms-fragment-limit?financial_year_start=2017'.format(sample_service.id), + headers=[('Content-Type', 'application/json'), create_authorization_header()]) + + json_resp = json.loads(response_get.get_data(as_text=True)) + assert response.status_code == 201 + assert response_get.status_code == 200 + assert json_resp['data']['financial_year_start'] == 2017 + assert json_resp['data']['free_sms_fragment_limit'] == 250 + + +def test_update_free_sms_fragment_limit(client, sample_service): + + data_old = {'financial_year_start': 2016, 'free_sms_fragment_limit': 1000} + response = client.post('service/{}/billing/free-sms-fragment-limit'.format(sample_service.id), + data=json.dumps(data_old), + headers=[('Content-Type', 'application/json'), create_authorization_header()]) + + data_new = {'financial_year_start': 2016, 'free_sms_fragment_limit': 9999} + response = client.post('service/{}/billing/free-sms-fragment-limit'.format(sample_service.id), + data=json.dumps(data_new), + headers=[('Content-Type', 'application/json'), create_authorization_header()]) + + response_get = client.get( + 'service/{}/billing/free-sms-fragment-limit?financial_year_start=2016'.format(sample_service.id), + headers=[('Content-Type', 'application/json'), create_authorization_header()]) + + json_resp = json.loads(response_get.get_data(as_text=True)) + + assert response.status_code == 201 + assert response_get.status_code == 200 + assert json_resp['data']['financial_year_start'] == 2016 + assert json_resp['data']['free_sms_fragment_limit'] == 9999 + + +def test_get_free_sms_fragment_limit_year_return_correct_data(client, sample_service): + years = [2016, 2017, 2018] + limits = [1000, 2000, 3000] + + for i in range(0, len(years)): + annual_billing = {'financial_year_start': years[i], 'free_sms_fragment_limit': limits[i]} + response = client.post('service/{}/billing/free-sms-fragment-limit'.format(sample_service.id), + data=json.dumps(annual_billing), + headers=[('Content-Type', 'application/json'), create_authorization_header()]) + + for i in range(0, len(years)): + response_get = client.get( + 'service/{}/billing/free-sms-fragment-limit?financial_year_start={}'.format(sample_service.id, years[i]), + headers=[('Content-Type', 'application/json'), create_authorization_header()]) + json_resp = json.loads(response_get.get_data(as_text=True)) + assert response_get.status_code == 200 + assert json_resp['data']['free_sms_fragment_limit'] == limits[i] + + +def test_get_free_sms_fragment_limit_for_all_years(client, sample_service): + years = [2016, 2017, 2018] + limits = [1000, 2000, 3000] + + for i in range(0, len(years)): + annual_billing = {'financial_year_start': years[i], 'free_sms_fragment_limit': limits[i]} + response = client.post('service/{}/billing/free-sms-fragment-limit'.format(sample_service.id), + data=json.dumps(annual_billing), + headers=[('Content-Type', 'application/json'), create_authorization_header()]) + + response_get = client.get( + # Not specify a particular year to return all data for that service + 'service/{}/billing/free-sms-fragment-limit'.format(sample_service.id), + headers=[('Content-Type', 'application/json'), create_authorization_header()]) + json_resp = json.loads(response_get.get_data(as_text=True)) + assert response_get.status_code == 200 + assert len(json_resp['data']) == 3 + print(json_resp) + for i in [0, 1, 2]: + assert json_resp['data'][i]['free_sms_fragment_limit'] == limits[i] + assert json_resp['data'][i]['financial_year_start'] == years[i] + + +def test_get_free_sms_fragment_limit_no_year_data_return_404(client, sample_service): + + response_get = client.get( + 'service/{}/billing/free-sms-fragment-limit?financial_year_start={}'.format(sample_service.id, 1999), + headers=[('Content-Type', 'application/json'), create_authorization_header()]) + json_resp = json.loads(response_get.get_data(as_text=True)) + + assert response_get.status_code == 404 + + +def test_get_free_sms_fragment_limit_unknown_service_id_return_404(client): + + response_get = client.get( + 'service/{}/billing/free-sms-fragment-limit'.format(uuid.uuid4()), + headers=[('Content-Type', 'application/json'), create_authorization_header()]) + json_resp = json.loads(response_get.get_data(as_text=True)) + assert response_get.status_code == 404 + + +def test_get_free_sms_fragment_limit_current_year(client, sample_service): + response = client.get( + 'service/{}/billing/free-sms-fragment-limit/current-year'.format(sample_service.id, True), + headers=[('Content-Type', 'application/json'), create_authorization_header()]) + json_resp = json.loads(response.get_data(as_text=True)) + + assert response.status_code == 200 + assert json_resp['data']['free_sms_fragment_limit'] == 250000 + + +def test_post_free_sms_fragment_limit_current_year(client, sample_service): + + data_new = {'free_sms_fragment_limit': 7777} + response = client.post('service/{}/billing/free-sms-fragment-limit'.format(sample_service.id), + data=json.dumps(data_new), + headers=[('Content-Type', 'application/json'), create_authorization_header()]) + + response_get = client.get( + 'service/{}/billing/free-sms-fragment-limit/current-year'.format(sample_service.id), + headers=[('Content-Type', 'application/json'), create_authorization_header()]) + json_resp = json.loads(response_get.get_data(as_text=True)) + + assert response.status_code == 201 + assert response_get.status_code == 200 + assert json_resp['data']['financial_year_start'] == get_current_financial_year_start_year() + assert json_resp['data']['free_sms_fragment_limit'] == 7777 diff --git a/tests/app/celery/test_tasks.py b/tests/app/celery/test_tasks.py index 39bce8e69..69f32c421 100644 --- a/tests/app/celery/test_tasks.py +++ b/tests/app/celery/test_tasks.py @@ -1398,7 +1398,15 @@ def test_process_ses_results(notify_db, notify_db_session, sample_email_template assert process_ses_results(response=response) is None +def test_process_ses_results_does_not_retry_if_errors(notify_db, mocker): + mocked = mocker.patch('app.celery.tasks.process_ses_results.retry') + response = json.loads(ses_notification_callback()) + process_ses_results(response=response) + assert mocked.call_count == 0 + + def test_process_ses_results_retry_called(notify_db, mocker): + mocker.patch("app.dao.notifications_dao.update_notification_status_by_reference", side_effect=Exception("EXPECTED")) mocked = mocker.patch('app.celery.tasks.process_ses_results.retry') response = json.loads(ses_notification_callback()) process_ses_results(response=response) diff --git a/tests/app/dao/test_annual_billing_dao.py b/tests/app/dao/test_annual_billing_dao.py new file mode 100644 index 000000000..10c6cd201 --- /dev/null +++ b/tests/app/dao/test_annual_billing_dao.py @@ -0,0 +1,57 @@ +from app.service.utils import get_current_financial_year_start_year +from app.models import AnnualBilling +from app.dao.annual_billing_dao import ( + dao_create_or_update_annual_billing_for_year, + dao_get_free_sms_fragment_limit_for_year, + dao_get_annual_billing +) + + +def test_get_sample_service_has_default_free_sms_fragment_limit(notify_db_session, sample_service): + + # when sample_service was created, it automatically create an entry in the annual_billing table + free_limit = dao_get_free_sms_fragment_limit_for_year(sample_service.id, get_current_financial_year_start_year()) + + assert free_limit.free_sms_fragment_limit == 250000 + assert free_limit.financial_year_start == get_current_financial_year_start_year() + assert free_limit.service_id == sample_service.id + + +def test_dao_update_free_sms_fragment_limit(notify_db_session, sample_service): + year = 1999 + old_limit = 1000 + new_limit = 9999 + + data = AnnualBilling( + free_sms_fragment_limit=old_limit, + financial_year_start=year, + service_id=sample_service.id, + ) + + dao_create_or_update_annual_billing_for_year(data) + data.free_sms_fragment_limit = new_limit + dao_create_or_update_annual_billing_for_year(data) + new_free_limit = dao_get_free_sms_fragment_limit_for_year(sample_service.id, year) + + assert new_free_limit.free_sms_fragment_limit == new_limit + + +def test_create_then_get_annual_billing(notify_db_session, sample_service): + years = [1999, 2001] + limits = [1000, 2000] + + for i in [0, 1]: + data = AnnualBilling( + free_sms_fragment_limit=limits[i], + financial_year_start=years[i], + service_id=sample_service.id, + ) + dao_create_or_update_annual_billing_for_year(data) + + free_limit = dao_get_annual_billing(sample_service.id) + assert len(free_limit) == 3 # sample service already has one entry + assert free_limit[0].free_sms_fragment_limit == 1000 + assert free_limit[0].financial_year_start == 1999 + assert free_limit[0].service_id == sample_service.id + assert free_limit[1].free_sms_fragment_limit == 2000 + assert free_limit[1].financial_year_start == 2001 diff --git a/tests/app/dao/test_services_dao.py b/tests/app/dao/test_services_dao.py index cbfbe9c45..70bc79eef 100644 --- a/tests/app/dao/test_services_dao.py +++ b/tests/app/dao/test_services_dao.py @@ -104,7 +104,7 @@ def test_cannot_create_two_services_with_same_name(sample_user): email_from="email_from1", message_limit=1000, restricted=False, - created_by=sample_user) + created_by=sample_user,) service2 = Service(name="service_name", email_from="email_from2", diff --git a/tests/app/service/test_rest.py b/tests/app/service/test_rest.py index 0ced56ec3..e317f7a24 100644 --- a/tests/app/service/test_rest.py +++ b/tests/app/service/test_rest.py @@ -37,6 +37,7 @@ from tests.app.db import ( create_service_sms_sender ) from tests.app.db import create_user +from app.service.utils import get_current_financial_year_start_year def test_get_service_list(client, service_factory): @@ -300,6 +301,7 @@ def test_create_service(client, sample_user): assert not json_resp['data']['research_mode'] assert json_resp['data']['dvla_organisation'] == '001' assert json_resp['data']['sms_sender'] == current_app.config['FROM_NUMBER'] + # TODO: Remove this after the new data is used assert json_resp['data']['free_sms_fragment_limit'] == current_app.config['FREE_SMS_TIER_FRAGMENT_COUNT'] service_db = Service.query.get(json_resp['data']['id']) @@ -365,6 +367,15 @@ def test_create_service_free_sms_fragment_limit_is_optional(client, sample_user) headers=headers) json_resp = json.loads(resp.get_data(as_text=True)) assert resp.status_code == 201 + + # Test data from the new annual billing table + service_id = json_resp['data']['id'] + annual_billing = client.get('service/{}/billing/free-sms-fragment-limit?financial_year_start={}' + .format(service_id, get_current_financial_year_start_year()), + headers=[('Content-Type', 'application/json'), create_authorization_header()]) + json_resp = json.loads(annual_billing.get_data(as_text=True)) + assert json_resp['data']['free_sms_fragment_limit'] == 9999 + # TODO: Remove this after the new data is used assert json_resp['data']['free_sms_fragment_limit'] == 9999 data2 = { @@ -385,6 +396,14 @@ def test_create_service_free_sms_fragment_limit_is_optional(client, sample_user) headers=headers) json_resp = json.loads(resp.get_data(as_text=True)) assert resp.status_code == 201 + # Test data from the new annual billing table + service_id = json_resp['data']['id'] + annual_billing = client.get('service/{}/billing/free-sms-fragment-limit?financial_year_start={}' + .format(service_id, get_current_financial_year_start_year()), + headers=[('Content-Type', 'application/json'), create_authorization_header()]) + json_resp = json.loads(annual_billing.get_data(as_text=True)) + assert json_resp['data']['free_sms_fragment_limit'] == current_app.config['FREE_SMS_TIER_FRAGMENT_COUNT'] + # TODO: Remove this after the new data is used assert json_resp['data']['free_sms_fragment_limit'] == current_app.config['FREE_SMS_TIER_FRAGMENT_COUNT'] @@ -623,6 +642,7 @@ def test_update_service_flags_will_remove_service_permissions(client, notify_db, assert set([p.permission for p in permissions]) == set([SMS_TYPE, EMAIL_TYPE]) +# TODO: Remove after new table is created and verified def test_update_service_free_sms_fragment_limit(client, notify_db, sample_service): org = Organisation(colour='#000000', logo='justice-league.png', name='Justice League') notify_db.session.add(org) diff --git a/tests/app/service/test_utils.py b/tests/app/service/test_utils.py new file mode 100644 index 000000000..4d59af22b --- /dev/null +++ b/tests/app/service/test_utils.py @@ -0,0 +1,15 @@ +from app.service.utils import get_current_financial_year_start_year +from freezegun import freeze_time + + +# see get_financial_year for conversion of financial years. +@freeze_time("2017-03-31 22:59:59.999999") +def test_get_current_financial_year_start_year_before_march(): + current_fy = get_current_financial_year_start_year() + assert current_fy == 2016 + + +@freeze_time("2017-03-31 23:00:00.000000") +def test_get_current_financial_year_start_year_after_april(): + current_fy = get_current_financial_year_start_year() + assert current_fy == 2017